rspec-expectations 2.13.0 → 2.99.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 (96) hide show
  1. checksums.yaml +15 -0
  2. data/Changelog.md +204 -23
  3. data/README.md +43 -87
  4. data/features/README.md +10 -10
  5. data/features/built_in_matchers/README.md +41 -41
  6. data/features/built_in_matchers/be.feature +40 -40
  7. data/features/built_in_matchers/be_within.feature +3 -3
  8. data/features/built_in_matchers/expect_change.feature +6 -6
  9. data/features/built_in_matchers/expect_error.feature +2 -2
  10. data/features/built_in_matchers/start_with.feature +1 -1
  11. data/features/built_in_matchers/throw_symbol.feature +11 -11
  12. data/features/built_in_matchers/yield.feature +18 -3
  13. data/features/custom_matchers/define_diffable_matcher.feature +1 -1
  14. data/features/custom_matchers/define_matcher_outside_rspec.feature +6 -6
  15. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +1 -1
  16. data/features/customized_message.feature +1 -1
  17. data/features/diffing.feature +1 -1
  18. data/features/step_definitions/additional_cli_steps.rb +10 -0
  19. data/features/support/env.rb +10 -1
  20. data/features/support/rubinius.rb +6 -0
  21. data/features/syntax_configuration.feature +3 -0
  22. data/features/test_frameworks/test_unit.feature +55 -17
  23. data/lib/rspec/expectations/caller_filter.rb +60 -0
  24. data/lib/rspec/{matchers → expectations}/configuration.rb +5 -3
  25. data/lib/rspec/expectations/deprecation.rb +20 -31
  26. data/lib/rspec/expectations/differ.rb +48 -9
  27. data/lib/rspec/expectations/expectation_target.rb +81 -15
  28. data/lib/rspec/expectations/extensions/object.rb +2 -12
  29. data/lib/rspec/expectations/fail_with.rb +11 -1
  30. data/lib/rspec/expectations/handler.rb +16 -7
  31. data/lib/rspec/expectations/syntax.rb +5 -7
  32. data/lib/rspec/expectations/version.rb +1 -1
  33. data/lib/rspec/expectations.rb +28 -2
  34. data/lib/rspec/matchers/be_close.rb +4 -1
  35. data/lib/rspec/matchers/built_in/base_matcher.rb +17 -10
  36. data/lib/rspec/matchers/built_in/be.rb +69 -32
  37. data/lib/rspec/matchers/built_in/be_within.rb +9 -3
  38. data/lib/rspec/matchers/built_in/change.rb +49 -3
  39. data/lib/rspec/matchers/built_in/has.rb +40 -7
  40. data/lib/rspec/matchers/built_in/have.rb +170 -5
  41. data/lib/rspec/matchers/built_in/include.rb +3 -11
  42. data/lib/rspec/matchers/built_in/match.rb +5 -0
  43. data/lib/rspec/matchers/built_in/match_array.rb +1 -1
  44. data/lib/rspec/matchers/built_in/raise_error.rb +34 -8
  45. data/lib/rspec/matchers/built_in/respond_to.rb +7 -1
  46. data/lib/rspec/matchers/built_in/satisfy.rb +7 -1
  47. data/lib/rspec/matchers/built_in/throw_symbol.rb +10 -2
  48. data/lib/rspec/matchers/built_in/yield.rb +102 -5
  49. data/lib/rspec/matchers/built_in.rb +2 -2
  50. data/lib/rspec/matchers/differentiate_block_method_types.rb +55 -0
  51. data/lib/rspec/matchers/dsl.rb +2 -1
  52. data/lib/rspec/matchers/match_aliases.rb +22 -0
  53. data/lib/rspec/matchers/matcher.rb +131 -10
  54. data/lib/rspec/matchers/operator_matcher.rb +70 -66
  55. data/lib/rspec/matchers/pretty.rb +11 -1
  56. data/lib/rspec/matchers/test_unit_integration.rb +28 -0
  57. data/lib/rspec/matchers.rb +175 -146
  58. data/lib/rspec-expectations.rb +5 -0
  59. data/spec/rspec/{matchers → expectations}/configuration_spec.rb +78 -91
  60. data/spec/rspec/expectations/differ_spec.rb +65 -6
  61. data/spec/rspec/expectations/expectation_target_spec.rb +72 -3
  62. data/spec/rspec/expectations/extensions/kernel_spec.rb +9 -5
  63. data/spec/rspec/expectations/fail_with_spec.rb +19 -0
  64. data/spec/rspec/expectations/handler_spec.rb +43 -22
  65. data/spec/rspec/expectations/syntax_spec.rb +51 -9
  66. data/spec/rspec/expectations_spec.rb +71 -0
  67. data/spec/rspec/matchers/base_matcher_spec.rb +33 -18
  68. data/spec/rspec/matchers/be_close_spec.rb +9 -6
  69. data/spec/rspec/matchers/be_spec.rb +146 -45
  70. data/spec/rspec/matchers/be_within_spec.rb +8 -0
  71. data/spec/rspec/matchers/change_spec.rb +107 -7
  72. data/spec/rspec/matchers/description_generation_spec.rb +38 -20
  73. data/spec/rspec/matchers/differentiate_block_method_types_spec.rb +39 -0
  74. data/spec/rspec/matchers/eq_spec.rb +1 -1
  75. data/spec/rspec/matchers/equal_spec.rb +26 -0
  76. data/spec/rspec/matchers/exist_spec.rb +9 -9
  77. data/spec/rspec/matchers/has_spec.rb +25 -1
  78. data/spec/rspec/matchers/have_spec.rb +411 -3
  79. data/spec/rspec/matchers/include_matcher_integration_spec.rb +2 -2
  80. data/spec/rspec/matchers/include_spec.rb +4 -4
  81. data/spec/rspec/matchers/match_array_spec.rb +1 -1
  82. data/spec/rspec/matchers/match_spec.rb +14 -1
  83. data/spec/rspec/matchers/matcher_spec.rb +213 -24
  84. data/spec/rspec/matchers/operator_matcher_spec.rb +56 -8
  85. data/spec/rspec/matchers/pretty_spec.rb +23 -0
  86. data/spec/rspec/matchers/raise_error_spec.rb +242 -102
  87. data/spec/rspec/matchers/respond_to_spec.rb +4 -4
  88. data/spec/rspec/matchers/satisfy_spec.rb +1 -1
  89. data/spec/rspec/matchers/start_with_end_with_spec.rb +2 -2
  90. data/spec/rspec/matchers/throw_symbol_spec.rb +14 -14
  91. data/spec/rspec/matchers/yield_spec.rb +81 -4
  92. data/spec/spec_helper.rb +5 -3
  93. data/spec/support/helper_methods.rb +42 -0
  94. data/spec/support/shared_examples.rb +42 -0
  95. metadata +40 -44
  96. data/spec/rspec/matchers/matchers_spec.rb +0 -37
@@ -17,13 +17,13 @@ module RSpec
17
17
  end
18
18
 
19
19
  def description
20
- "include#{expected_to_sentence}"
20
+ "include#{to_sentence expected}"
21
21
  end
22
22
 
23
23
  def diffable?
24
24
  # Matchers do not diff well, since diff uses their inspect
25
25
  # output, which includes their instance variables and such.
26
- @expected.none? { |e| is_a_matcher?(e) }
26
+ @expected.none? { |e| RSpec::Matchers.is_a_matcher?(e) }
27
27
  end
28
28
 
29
29
  private
@@ -53,15 +53,7 @@ module RSpec
53
53
  end
54
54
 
55
55
  def comparing_with_matcher?(actual, expected)
56
- actual.is_a?(Array) && is_a_matcher?(expected)
57
- end
58
-
59
- def is_a_matcher?(object)
60
- return false if object.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
61
-
62
- [:failure_message_for_should, :failure_message].any? do |msg|
63
- object.respond_to?(msg)
64
- end && object.respond_to?(:matches?)
56
+ actual.is_a?(Array) && RSpec::Matchers.is_a_matcher?(expected)
65
57
  end
66
58
  end
67
59
  end
@@ -6,6 +6,11 @@ module RSpec
6
6
  def match(expected, actual)
7
7
  actual.match expected
8
8
  end
9
+
10
+ def diffable?
11
+ true
12
+ end
13
+
9
14
  end
10
15
  end
11
16
  end
@@ -27,7 +27,7 @@ module RSpec
27
27
  end
28
28
 
29
29
  def description
30
- "contain exactly #{_pretty_print(expected)}"
30
+ "contain exactly#{to_sentence(expected)}"
31
31
  end
32
32
 
33
33
  private
@@ -2,6 +2,8 @@ module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
4
  class RaiseError
5
+ include MatchAliases
6
+
5
7
  def initialize(expected_error_or_message=Exception, expected_message=nil, &block)
6
8
  @block = block
7
9
  @actual_error = nil
@@ -14,19 +16,35 @@ module RSpec
14
16
  end
15
17
 
16
18
  def matches?(given_proc, negative_expectation = false)
19
+ if negative_expectation && (expecting_specific_exception? || @expected_message)
20
+ what_to_deprecate = if expecting_specific_exception? && @expected_message
21
+ "`expect { }.not_to raise_error(SpecificErrorClass, message)`"
22
+ elsif expecting_specific_exception?
23
+ "`expect { }.not_to raise_error(SpecificErrorClass)`"
24
+ elsif @expected_message
25
+ "`expect { }.not_to raise_error(message)`"
26
+ end
27
+
28
+ RSpec.deprecate(
29
+ what_to_deprecate,
30
+ :replacement => "`expect { }.not_to raise_error` (with no args)"
31
+ )
32
+ end
17
33
  @raised_expected_error = false
18
34
  @with_expected_message = false
19
35
  @eval_block = false
20
36
  @eval_block_passed = false
37
+ unless given_proc.respond_to?(:call)
38
+ ::Kernel.warn "`raise_error` was called with non-proc object #{given_proc.inspect}"
39
+ return false
40
+ end
21
41
  begin
22
42
  given_proc.call
23
- rescue @expected_error => @actual_error
24
- @raised_expected_error = true
25
- @with_expected_message = verify_message
26
43
  rescue Exception => @actual_error
27
- # This clause should be empty, but rcov will not report it as covered
28
- # unless something (anything) is executed within the clause
29
- "http://eigenclass.org/hiki.rb?rcov-0.8.0"
44
+ if @actual_error == @expected_error || @expected_error === @actual_error
45
+ @raised_expected_error = true
46
+ @with_expected_message = verify_message
47
+ end
30
48
  end
31
49
 
32
50
  unless negative_expectation
@@ -35,7 +53,6 @@ module RSpec
35
53
  ensure
36
54
  return (@raised_expected_error & @with_expected_message) ? (@eval_block ? @eval_block_passed : true) : false
37
55
  end
38
- alias == matches?
39
56
 
40
57
  def does_not_match?(given_proc)
41
58
  !matches?(given_proc, :negative_expectation)
@@ -74,12 +91,17 @@ module RSpec
74
91
  "raise #{expected_error}"
75
92
  end
76
93
 
94
+ # @private
95
+ def supports_block_expectations?
96
+ true
97
+ end
98
+
77
99
  private
78
100
 
79
101
  def expected_error
80
102
  case @expected_message
81
103
  when nil
82
- @expected_error
104
+ @expected_error.inspect
83
105
  when Regexp
84
106
  "#{@expected_error} with message matching #{@expected_message.inspect}"
85
107
  else
@@ -101,6 +123,10 @@ module RSpec
101
123
  *backtrace
102
124
  ].join("\n # ")
103
125
  end
126
+
127
+ def expecting_specific_exception?
128
+ @expected_error != Exception
129
+ end
104
130
  end
105
131
  end
106
132
  end
@@ -2,6 +2,8 @@ module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
4
  class RespondTo
5
+ include MatchAliases
6
+
5
7
  def initialize(*names)
6
8
  @names = names
7
9
  @expected_arity = nil
@@ -10,7 +12,6 @@ module RSpec
10
12
  def matches?(actual)
11
13
  find_failing_method_names(actual, :reject).empty?
12
14
  end
13
- alias == matches?
14
15
 
15
16
  def does_not_match?(actual)
16
17
  find_failing_method_names(actual, :select).empty?
@@ -38,6 +39,11 @@ module RSpec
38
39
  end
39
40
  alias :arguments :argument
40
41
 
42
+ # @private
43
+ def supports_block_expectations?
44
+ false
45
+ end
46
+
41
47
  private
42
48
 
43
49
  def find_failing_method_names(actual, filter_method)
@@ -2,6 +2,8 @@ module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
4
  class Satisfy
5
+ include MatchAliases
6
+
5
7
  def initialize(&block)
6
8
  @block = block
7
9
  end
@@ -11,7 +13,6 @@ module RSpec
11
13
  @actual = actual
12
14
  @block.call(actual)
13
15
  end
14
- alias == matches?
15
16
 
16
17
  def failure_message_for_should
17
18
  "expected #{@actual} to satisfy block"
@@ -24,6 +25,11 @@ module RSpec
24
25
  def description
25
26
  "satisfy block"
26
27
  end
28
+
29
+ # @private
30
+ def supports_block_expectations?
31
+ false
32
+ end
27
33
  end
28
34
  end
29
35
  end
@@ -2,6 +2,8 @@ module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
4
  class ThrowSymbol
5
+ include MatchAliases
6
+
5
7
  def initialize(expected_symbol = nil, expected_arg=nil)
6
8
  @expected_symbol = expected_symbol
7
9
  @expected_arg = expected_arg
@@ -51,7 +53,6 @@ module RSpec
51
53
  end
52
54
  end
53
55
  end
54
- alias == matches?
55
56
 
56
57
  def failure_message_for_should
57
58
  "expected #{expected} to be thrown, got #{caught}"
@@ -65,7 +66,14 @@ module RSpec
65
66
  "throw #{expected}"
66
67
  end
67
68
 
68
- private
69
+ # @api private
70
+ # Indicates this matcher matches against a block.
71
+ # @return [True]
72
+ def supports_block_expectations?
73
+ true
74
+ end
75
+
76
+ private
69
77
 
70
78
  def expected(symbol_desc = 'a Symbol')
71
79
  throw_description(@expected_symbol || symbol_desc, @expected_arg)
@@ -65,17 +65,97 @@ module RSpec
65
65
  end
66
66
 
67
67
  class YieldControl < BaseMatcher
68
+ def initialize
69
+ @expectation_type = nil
70
+ @expected_yields_count = nil
71
+ end
72
+
68
73
  def matches?(block)
69
74
  probe = YieldProbe.probe(block)
70
- probe.yielded_once?(:yield_control)
75
+
76
+ if @expectation_type
77
+ probe.num_yields.send(@expectation_type, @expected_yields_count)
78
+ else
79
+ probe.yielded_once?(:yield_control)
80
+ end
81
+ end
82
+
83
+ def once
84
+ exactly(1)
85
+ self
86
+ end
87
+
88
+ def twice
89
+ exactly(2)
90
+ self
91
+ end
92
+
93
+ def exactly(number)
94
+ set_expected_yields_count(:==, number)
95
+ self
96
+ end
97
+
98
+ def at_most(number)
99
+ set_expected_yields_count(:<=, number)
100
+ self
101
+ end
102
+
103
+ def at_least(number)
104
+ set_expected_yields_count(:>=, number)
105
+ self
106
+ end
107
+
108
+ def times
109
+ self
71
110
  end
72
111
 
73
112
  def failure_message_for_should
74
- "expected given block to yield control"
113
+ 'expected given block to yield control'.tap do |failure_message|
114
+ failure_message << relativity_failure_message
115
+ end
75
116
  end
76
117
 
77
118
  def failure_message_for_should_not
78
- "expected given block not to yield control"
119
+ 'expected given block not to yield control'.tap do |failure_message|
120
+ failure_message << relativity_failure_message
121
+ end
122
+ end
123
+
124
+ # @private
125
+ def supports_block_expectations?
126
+ true
127
+ end
128
+
129
+ private
130
+
131
+ def set_expected_yields_count(relativity, n)
132
+ @expectation_type = relativity
133
+ @expected_yields_count = case n
134
+ when Numeric then n
135
+ when :once then 1
136
+ when :twice then 2
137
+ end
138
+ end
139
+
140
+ def relativity_failure_message
141
+ return '' unless @expected_yields_count
142
+ " #{human_readable_expecation_type}#{human_readable_count}"
143
+ end
144
+
145
+ def human_readable_expecation_type
146
+ case @expectation_type
147
+ when :<= then 'at most '
148
+ when :>= then 'at least '
149
+ else ''
150
+ end
151
+ end
152
+
153
+ def human_readable_count
154
+ case @expected_yields_count
155
+ when 1 then "once"
156
+ when 2 then "twice"
157
+ else "#{@expected_yields_count} times"
158
+ end
79
159
  end
80
160
  end
81
161
 
@@ -94,6 +174,11 @@ module RSpec
94
174
  "expected given block not to yield with no arguments, but did"
95
175
  end
96
176
 
177
+ # @private
178
+ def supports_block_expectations?
179
+ true
180
+ end
181
+
97
182
  private
98
183
 
99
184
  def failure_reason
@@ -106,6 +191,8 @@ module RSpec
106
191
  end
107
192
 
108
193
  class YieldWithArgs
194
+ include MatchAliases
195
+
109
196
  def initialize(*args)
110
197
  @expected = args
111
198
  end
@@ -115,7 +202,6 @@ module RSpec
115
202
  @actual = @probe.single_yield_args
116
203
  @probe.yielded_once?(:yield_with_args) && args_match?
117
204
  end
118
- alias == matches?
119
205
 
120
206
  def failure_message_for_should
121
207
  "expected given block to yield with arguments, but #{positive_failure_reason}"
@@ -131,6 +217,11 @@ module RSpec
131
217
  desc
132
218
  end
133
219
 
220
+ # @private
221
+ def supports_block_expectations?
222
+ true
223
+ end
224
+
134
225
  private
135
226
 
136
227
  def positive_failure_reason
@@ -176,6 +267,8 @@ module RSpec
176
267
  end
177
268
 
178
269
  class YieldSuccessiveArgs
270
+ include MatchAliases
271
+
179
272
  def initialize(*args)
180
273
  @expected = args
181
274
  end
@@ -185,7 +278,6 @@ module RSpec
185
278
  @actual = @probe.successive_yield_args
186
279
  args_match?
187
280
  end
188
- alias == matches?
189
281
 
190
282
  def failure_message_for_should
191
283
  "expected given block to yield successively with arguments, but yielded with unexpected arguments" +
@@ -205,6 +297,11 @@ module RSpec
205
297
  desc
206
298
  end
207
299
 
300
+ # @private
301
+ def supports_block_expectations?
302
+ true
303
+ end
304
+
208
305
  private
209
306
 
210
307
  def args_match?
@@ -4,8 +4,8 @@ module RSpec
4
4
  require 'rspec/matchers/built_in/base_matcher'
5
5
  autoload :BeAnInstanceOf, 'rspec/matchers/built_in/be_instance_of'
6
6
  autoload :Be, 'rspec/matchers/built_in/be'
7
- autoload :BeTrue, 'rspec/matchers/built_in/be'
8
- autoload :BeFalse, 'rspec/matchers/built_in/be'
7
+ autoload :BeTruthy, 'rspec/matchers/built_in/be'
8
+ autoload :BeFalsey, 'rspec/matchers/built_in/be'
9
9
  autoload :BeNil, 'rspec/matchers/built_in/be'
10
10
  autoload :BeComparedTo, 'rspec/matchers/built_in/be'
11
11
  autoload :BePredicate, 'rspec/matchers/built_in/be'
@@ -0,0 +1,55 @@
1
+ module RSpec
2
+ module Matchers
3
+ # Evaluates a block in order to determine what methods, if any,
4
+ # it defines as instance methods (using `def foo`) vs singleton
5
+ # methods (using `def self.foo`).
6
+ #
7
+ # @api private
8
+ class DifferentiateBlockMethodTypes
9
+ def initialize(*block_args, &block)
10
+ @block_args = block_args
11
+ @block = block
12
+
13
+ ignore_macro_methods
14
+
15
+ capture_added_methods(singletons_singleton_class, singleton_methods)
16
+ capture_added_methods(singleton_class, instance_methods)
17
+
18
+ singleton_class.class_exec(*block_args, &block)
19
+ end
20
+
21
+ def singleton_methods
22
+ @singleton_methods ||= []
23
+ end
24
+
25
+ def instance_methods
26
+ @instance_methods ||= []
27
+ end
28
+
29
+ private
30
+
31
+ def capture_added_methods(object, method_list)
32
+ object.__send__(:define_method, :singleton_method_added) do |method_name|
33
+ method_list << method_name
34
+ end
35
+
36
+ method_list.delete(:singleton_method_added)
37
+ end
38
+
39
+ unless method_defined?(:singleton_class)
40
+ def singleton_class
41
+ class << self; self; end
42
+ end
43
+ end
44
+
45
+ def singletons_singleton_class
46
+ class << singleton_class; self; end
47
+ end
48
+
49
+ def ignore_macro_methods
50
+ def singleton_class.method_missing(*); self; end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -7,7 +7,8 @@ module RSpec
7
7
  matcher_template = RSpec::Matchers::DSL::Matcher.new(name, &declarations)
8
8
  define_method name do |*expected|
9
9
  matcher = matcher_template.for_expected(*expected)
10
- matcher.matcher_execution_context = @matcher_execution_context ||= self
10
+ @matcher_execution_context ||= self
11
+ matcher.instance_variable_set(:@matcher_execution_context, @matcher_execution_context)
11
12
  matcher
12
13
  end
13
14
  end
@@ -0,0 +1,22 @@
1
+ module RSpec
2
+ module Matchers
3
+ module MatchAliases
4
+ def ==(other)
5
+ return true if equal?(other)
6
+
7
+ matched = matches?(other)
8
+
9
+ if matched
10
+ RSpec.deprecate("Using `matcher == value` as an alias for `#matches?`", :replacement => "`matcher === value`")
11
+ end
12
+
13
+ matched
14
+ end
15
+
16
+ def ===(other)
17
+ matches?(other)
18
+ end
19
+ end
20
+ end
21
+ end
22
+