rspec-expectations 2.12.1 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/Changelog.md +31 -0
  2. data/README.md +1 -1
  3. data/features/built_in_matchers/be.feature +6 -4
  4. data/features/built_in_matchers/be_within.feature +3 -1
  5. data/features/built_in_matchers/cover.feature +2 -0
  6. data/features/built_in_matchers/end_with.feature +2 -0
  7. data/features/built_in_matchers/equality.feature +9 -15
  8. data/features/built_in_matchers/exist.feature +2 -0
  9. data/features/built_in_matchers/expect_error.feature +14 -8
  10. data/features/built_in_matchers/have.feature +11 -5
  11. data/features/built_in_matchers/include.feature +53 -0
  12. data/features/built_in_matchers/match.feature +2 -0
  13. data/features/built_in_matchers/operators.feature +17 -11
  14. data/features/built_in_matchers/predicates.feature +21 -13
  15. data/features/built_in_matchers/respond_to.feature +7 -1
  16. data/features/built_in_matchers/satisfy.feature +2 -0
  17. data/features/built_in_matchers/start_with.feature +2 -0
  18. data/features/built_in_matchers/throw_symbol.feature +6 -0
  19. data/features/built_in_matchers/types.feature +8 -6
  20. data/lib/rspec/expectations/deprecation.rb +1 -1
  21. data/lib/rspec/expectations/differ.rb +8 -8
  22. data/lib/rspec/expectations/fail_with.rb +17 -3
  23. data/lib/rspec/expectations/syntax.rb +46 -0
  24. data/lib/rspec/expectations/version.rb +1 -1
  25. data/lib/rspec/matchers/built_in/be.rb +7 -3
  26. data/lib/rspec/matchers/built_in/be_within.rb +13 -4
  27. data/lib/rspec/matchers/built_in/change.rb +2 -2
  28. data/lib/rspec/matchers/built_in/equal.rb +5 -1
  29. data/lib/rspec/matchers/built_in/exist.rb +1 -1
  30. data/lib/rspec/matchers/built_in/have.rb +8 -8
  31. data/lib/rspec/matchers/built_in/include.rb +19 -3
  32. data/lib/rspec/matchers/built_in/respond_to.rb +1 -1
  33. data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +1 -1
  34. data/lib/rspec/matchers/matcher.rb +4 -3
  35. data/lib/rspec/matchers/operator_matcher.rb +1 -1
  36. data/lib/rspec/matchers/pretty.rb +5 -1
  37. data/spec/rspec/expectations/differ_spec.rb +8 -15
  38. data/spec/rspec/expectations/expectation_target_spec.rb +18 -8
  39. data/spec/rspec/expectations/extensions/kernel_spec.rb +15 -15
  40. data/spec/rspec/expectations/fail_with_spec.rb +41 -16
  41. data/spec/rspec/expectations/handler_spec.rb +13 -13
  42. data/spec/rspec/expectations/syntax_spec.rb +70 -8
  43. data/spec/rspec/matchers/base_matcher_spec.rb +14 -12
  44. data/spec/rspec/matchers/be_close_spec.rb +1 -1
  45. data/spec/rspec/matchers/be_instance_of_spec.rb +14 -8
  46. data/spec/rspec/matchers/be_kind_of_spec.rb +12 -8
  47. data/spec/rspec/matchers/be_spec.rb +212 -148
  48. data/spec/rspec/matchers/be_within_spec.rb +91 -42
  49. data/spec/rspec/matchers/change_spec.rb +52 -38
  50. data/spec/rspec/matchers/configuration_spec.rb +19 -15
  51. data/spec/rspec/matchers/cover_spec.rb +19 -19
  52. data/spec/rspec/matchers/description_generation_spec.rb +86 -86
  53. data/spec/rspec/matchers/dsl_spec.rb +7 -7
  54. data/spec/rspec/matchers/eq_spec.rb +17 -11
  55. data/spec/rspec/matchers/eql_spec.rb +10 -10
  56. data/spec/rspec/matchers/equal_spec.rb +27 -9
  57. data/spec/rspec/matchers/exist_spec.rb +35 -21
  58. data/spec/rspec/matchers/has_spec.rb +33 -29
  59. data/spec/rspec/matchers/have_spec.rb +165 -151
  60. data/spec/rspec/matchers/include_matcher_integration_spec.rb +30 -0
  61. data/spec/rspec/matchers/include_spec.rb +282 -124
  62. data/spec/rspec/matchers/match_array_spec.rb +90 -49
  63. data/spec/rspec/matchers/match_spec.rb +21 -21
  64. data/spec/rspec/matchers/matcher_spec.rb +85 -48
  65. data/spec/rspec/matchers/matchers_spec.rb +12 -6
  66. data/spec/rspec/matchers/method_missing_spec.rb +5 -1
  67. data/spec/rspec/matchers/operator_matcher_spec.rb +216 -237
  68. data/spec/rspec/matchers/raise_error_spec.rb +132 -132
  69. data/spec/rspec/matchers/respond_to_spec.rb +109 -112
  70. data/spec/rspec/matchers/satisfy_spec.rb +16 -16
  71. data/spec/rspec/matchers/start_with_end_with_spec.rb +36 -32
  72. data/spec/rspec/matchers/throw_symbol_spec.rb +24 -24
  73. data/spec/rspec/matchers/yield_spec.rb +7 -7
  74. data/spec/spec_helper.rb +46 -19
  75. data/spec/support/in_sub_process.rb +27 -20
  76. metadata +81 -83
@@ -3,8 +3,10 @@ Feature: satisfy matcher
3
3
  The satisfy matcher is extremely flexible and can handle almost anything
4
4
  you want to specify. It passes if the block you provide returns true:
5
5
 
6
+ ```ruby
6
7
  10.should satisfy { |v| v % 5 == 0 }
7
8
  7.should_not satisfy { |v| v % 5 == 0 }
9
+ ```
8
10
 
9
11
  This flexibility comes at a cost, however: the failure message
10
12
  ("expected [actual] to satisfy block") is not very descriptive
@@ -3,9 +3,11 @@ Feature: start_with matcher
3
3
  Use the `start_with` matcher to specify that a string or array starts with
4
4
  the expected characters or elements.
5
5
 
6
+ ```ruby
6
7
  "this string".should start_with("this")
7
8
  "this string".should_not start_with("that")
8
9
  [0,1,2].should start_with(0, 1)
10
+ ```
9
11
 
10
12
  Scenario: with a string
11
13
  Given a file named "example_spec.rb" with:
@@ -3,16 +3,22 @@ Feature: throw_symbol matcher
3
3
  The throw_symbol matcher is used to specify that a block of code
4
4
  throws a symbol. The most basic form passes if any symbol is thrown:
5
5
 
6
+ ```ruby
6
7
  expect { throw :foo }.to throw_symbol
8
+ ```
7
9
 
8
10
  You'll often want to specify that a particular symbol is thrown:
9
11
 
12
+ ```ruby
10
13
  expect { throw :foo }.to throw_symbol(:foo)
14
+ ```
11
15
 
12
16
  If you care about the additional argument given to throw, you can
13
17
  specify that as well:
14
18
 
19
+ ```ruby
15
20
  expect { throw :foo, 7 }.to throw_symbol(:foo, 7)
21
+ ```
16
22
 
17
23
  Scenario: basic usage
18
24
  Given a file named "throw_symbol_matcher_spec.rb" with:
@@ -2,18 +2,20 @@ Feature: specify types of objects
2
2
 
3
3
  rspec-expectations includes two matchers to specify types of objects:
4
4
 
5
- * obj.should be_kind_of(type): calls obj.kind_of?(type), which returns
5
+ * `obj.should be_kind_of(type)`: calls `obj.kind_of?(type)`, which returns
6
6
  true if type is in obj's class hierarchy or is a module and is
7
7
  included in a class in obj's class hierarchy.
8
- * obj.should be_instance_of(type): calls obj.instance_of?(type), which
8
+ * `obj.should be_instance_of(type)`: calls `obj.instance_of?(type)`, which
9
9
  returns true if and only if type if obj's class.
10
10
 
11
11
  Both of these matchers have aliases:
12
12
 
13
- * obj.should be_a_kind_of(type) # same as obj.should be_kind_of(type)
14
- * obj.should be_a(type) # same as obj.should be_kind_of(type)
15
- * obj.should be_an(type) # same as obj.should be_kind_of(type)
16
- * obj.should be_an_instance_of(type) # same as obj.should be_instance_of(type)
13
+ ```ruby
14
+ obj.should be_a_kind_of(type) # same as obj.should be_kind_of(type)
15
+ obj.should be_a(type) # same as obj.should be_kind_of(type)
16
+ obj.should be_an(type) # same as obj.should be_kind_of(type)
17
+ obj.should be_an_instance_of(type) # same as obj.should be_instance_of(type)
18
+ ```
17
19
 
18
20
  Scenario: be_(a_)kind_of matcher
19
21
  Given a file named "be_kind_of_matcher_spec.rb" with:
@@ -31,7 +31,7 @@ ADDITIONAL
31
31
  # is also defined in rspec-core, but we can't assume it's loaded since
32
32
  # rspec-expectations should be usable w/o rspec-core.
33
33
  def warn_deprecation(message)
34
- send :warn, message
34
+ warn(message)
35
35
  end
36
36
  end
37
37
  end
@@ -25,7 +25,13 @@ module RSpec
25
25
  # diff includes lines of context. Otherwise, we might print
26
26
  # redundant lines.
27
27
  if (context_lines > 0) and hunk.overlaps?(oldhunk)
28
- hunk.unshift(oldhunk)
28
+ if hunk.respond_to?(:merge)
29
+ # diff-lcs 1.2.x
30
+ hunk.merge(oldhunk)
31
+ else
32
+ # diff-lcs 1.1.3
33
+ hunk.unshift(oldhunk)
34
+ end
29
35
  else
30
36
  output << oldhunk.diff(format)
31
37
  end
@@ -42,13 +48,7 @@ module RSpec
42
48
  def diff_as_object(actual, expected)
43
49
  actual_as_string = object_to_string(actual)
44
50
  expected_as_string = object_to_string(expected)
45
- diff = diff_as_string(actual_as_string, expected_as_string)
46
-
47
- if diff.empty?
48
- "#{actual}.==(#{expected}) returned false even though the diff " \
49
- "between #{actual} and #{expected} is empty. Check the " \
50
- "implementation of #{actual}.==."
51
- else
51
+ if diff = diff_as_string(actual_as_string, expected_as_string)
52
52
  color_diff diff
53
53
  end
54
54
  end
@@ -22,8 +22,7 @@ module RSpec
22
22
  if actual && expected
23
23
  if all_strings?(actual, expected)
24
24
  if any_multiline_strings?(actual, expected)
25
- expected = expected.join(',') if Array === expected
26
- message << "\nDiff:" << differ.diff_as_string(actual, expected)
25
+ message << "\nDiff:" << differ.diff_as_string(coerce_to_string(actual), coerce_to_string(expected))
27
26
  end
28
27
  elsif no_procs?(actual, expected) && no_numbers?(actual, expected)
29
28
  message << "\nDiff:" << differ.diff_as_object(actual, expected)
@@ -44,12 +43,27 @@ module RSpec
44
43
  end
45
44
 
46
45
  def any_multiline_strings?(*args)
47
- all_strings?(*args) && args.any? {|a| a =~ /\n/}
46
+ all_strings?(*args) && args.flatten.any? { |a| multiline?(a) }
48
47
  end
49
48
 
50
49
  def no_numbers?(*args)
51
50
  args.flatten.none? {|a| Numeric === a}
52
51
  end
52
+
53
+ def coerce_to_string(string_or_array)
54
+ return string_or_array unless Array === string_or_array
55
+ string_or_array.join(',')
56
+ end
57
+
58
+ if String.method_defined?(:encoding)
59
+ def multiline?(string)
60
+ string.include?("\n".encode(string.encoding))
61
+ end
62
+ else
63
+ def multiline?(string)
64
+ string.include?("\n")
65
+ end
66
+ end
53
67
  end
54
68
  end
55
69
  end
@@ -113,6 +113,52 @@ module RSpec
113
113
  def expect_enabled?(syntax_host = ::RSpec::Matchers)
114
114
  syntax_host.method_defined?(:expect)
115
115
  end
116
+
117
+ # @api private
118
+ # Generates a positive expectation expression.
119
+ def positive_expression(target_expression, matcher_expression)
120
+ expression_generator.positive_expression(target_expression, matcher_expression)
121
+ end
122
+
123
+ # @api private
124
+ # Generates a negative expectation expression.
125
+ def negative_expression(target_expression, matcher_expression)
126
+ expression_generator.negative_expression(target_expression, matcher_expression)
127
+ end
128
+
129
+ # @api private
130
+ # Selects which expression generator to use based on the configured syntax.
131
+ def expression_generator
132
+ if expect_enabled?
133
+ ExpectExpressionGenerator
134
+ else
135
+ ShouldExpressionGenerator
136
+ end
137
+ end
138
+
139
+ # @api private
140
+ # Generates expectation expressions for the `should` syntax.
141
+ module ShouldExpressionGenerator
142
+ def self.positive_expression(target_expression, matcher_expression)
143
+ "#{target_expression}.should #{matcher_expression}"
144
+ end
145
+
146
+ def self.negative_expression(target_expression, matcher_expression)
147
+ "#{target_expression}.should_not #{matcher_expression}"
148
+ end
149
+ end
150
+
151
+ # @api private
152
+ # Generates expectation expressions for the `expect` syntax.
153
+ module ExpectExpressionGenerator
154
+ def self.positive_expression(target_expression, matcher_expression)
155
+ "expect(#{target_expression}).to #{matcher_expression}"
156
+ end
157
+
158
+ def self.negative_expression(target_expression, matcher_expression)
159
+ "expect(#{target_expression}).not_to #{matcher_expression}"
160
+ end
161
+ end
116
162
  end
117
163
  end
118
164
  end
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Expectations
3
3
  # @private
4
4
  module Version
5
- STRING = '2.12.1'
5
+ STRING = '2.13.0'
6
6
  end
7
7
  end
8
8
  end
@@ -62,7 +62,7 @@ module RSpec
62
62
  "expected #{@actual.inspect} to evaluate to false"
63
63
  end
64
64
 
65
- [:==, :<, :<=, :>=, :>, :===].each do |operator|
65
+ [:==, :<, :<=, :>=, :>, :===, :=~].each do |operator|
66
66
  define_method operator do |operand|
67
67
  BeComparedTo.new(operand, operator)
68
68
  end
@@ -99,7 +99,7 @@ module RSpec
99
99
 
100
100
  def matches?(actual)
101
101
  @actual = actual
102
- @actual.send @operator, @expected
102
+ @actual.__send__ @operator, @expected
103
103
  end
104
104
 
105
105
  def failure_message_for_should
@@ -108,7 +108,7 @@ module RSpec
108
108
 
109
109
  def failure_message_for_should_not
110
110
  message = <<-MESSAGE
111
- 'should_not be #{@operator} #{@expected}' not only FAILED,
111
+ `#{negative_expectation_expression}` not only FAILED,
112
112
  it is a bit confusing.
113
113
  MESSAGE
114
114
 
@@ -120,6 +120,10 @@ it is a bit confusing.
120
120
  def description
121
121
  "be #{@operator} #{expected_to_sentence}#{args_to_sentence}"
122
122
  end
123
+
124
+ def negative_expectation_expression
125
+ Expectations::Syntax.negative_expression("actual", "be #{@operator} #{@expected}")
126
+ end
123
127
  end
124
128
 
125
129
  class BePredicate < Be
@@ -8,14 +8,23 @@ module RSpec
8
8
 
9
9
  def matches?(actual)
10
10
  @actual = actual
11
- raise needs_expected unless defined? @expected
11
+ raise needs_expected unless defined? @expected
12
12
  raise needs_subtractable unless @actual.respond_to? :-
13
- (@actual - @expected).abs <= @delta
13
+ (@actual - @expected).abs <= @tolerance
14
14
  end
15
15
  alias == matches?
16
16
 
17
17
  def of(expected)
18
- @expected = expected
18
+ @expected = expected
19
+ @tolerance = @delta
20
+ @unit = ''
21
+ self
22
+ end
23
+
24
+ def percent_of(expected)
25
+ @expected = expected
26
+ @tolerance = @delta * @expected / 100
27
+ @unit = '%'
19
28
  self
20
29
  end
21
30
 
@@ -28,7 +37,7 @@ module RSpec
28
37
  end
29
38
 
30
39
  def description
31
- "be within #{@delta} of #{@expected}"
40
+ "be within #{@delta}#{@unit} of #{@expected}"
32
41
  end
33
42
 
34
43
  private
@@ -28,7 +28,7 @@ MESSAGE
28
28
 
29
29
  def evaluate_value_proc
30
30
  case val = @value_proc.call
31
- when Enumerable
31
+ when Enumerable, String
32
32
  val.dup
33
33
  else
34
34
  val
@@ -72,7 +72,7 @@ MESSAGE
72
72
  def by_at_most(maximum)
73
73
  @maximum = maximum
74
74
  self
75
- end
75
+ end
76
76
 
77
77
  def to(to)
78
78
  @eval_after = true
@@ -14,7 +14,7 @@ expected #{inspect_object(expected)}
14
14
 
15
15
  Compared using equal?, which compares object identity,
16
16
  but expected and actual are not the same object. Use
17
- 'actual.should eq(expected)' if you don't care about
17
+ `#{eq_expression}` if you don't care about
18
18
  object identity in this example.
19
19
 
20
20
  MESSAGE
@@ -38,6 +38,10 @@ MESSAGE
38
38
  def inspect_object(o)
39
39
  "#<#{o.class}:#{o.object_id}> => #{o.inspect}"
40
40
  end
41
+
42
+ def eq_expression
43
+ Expectations::Syntax.positive_expression("actual", "eq(expected)")
44
+ end
41
45
  end
42
46
  end
43
47
  end
@@ -9,7 +9,7 @@ module RSpec
9
9
  def matches?(actual)
10
10
  @actual = actual
11
11
  predicates = [:exist?, :exists?].select { |p| @actual.respond_to?(p) }
12
- existence_values = predicates.map { |p| @actual.send(p, *@expected) }
12
+ existence_values = predicates.map { |p| @actual.__send__(p, *@expected) }
13
13
  uniq_truthy_values = existence_values.map { |v| !!v }.uniq
14
14
 
15
15
  case uniq_truthy_values.size
@@ -24,7 +24,7 @@ module RSpec
24
24
  collection = determine_collection(collection_or_owner)
25
25
  query_method = determine_query_method(collection)
26
26
  raise not_a_collection unless query_method
27
- @actual = collection.send(query_method)
27
+ @actual = collection.__send__(query_method)
28
28
  case @relativity
29
29
  when :at_least then @actual >= @expected
30
30
  when :at_most then @actual <= @expected
@@ -35,13 +35,13 @@ module RSpec
35
35
 
36
36
  def determine_collection(collection_or_owner)
37
37
  if collection_or_owner.respond_to?(@collection_name)
38
- collection_or_owner.send(@collection_name, *@args, &@block)
38
+ collection_or_owner.__send__(@collection_name, *@args, &@block)
39
39
  elsif (@plural_collection_name && collection_or_owner.respond_to?(@plural_collection_name))
40
- collection_or_owner.send(@plural_collection_name, *@args, &@block)
40
+ collection_or_owner.__send__(@plural_collection_name, *@args, &@block)
41
41
  elsif determine_query_method(collection_or_owner)
42
42
  collection_or_owner
43
43
  else
44
- collection_or_owner.send(@collection_name, *@args, &@block)
44
+ collection_or_owner.__send__(@collection_name, *@args, &@block)
45
45
  end
46
46
  end
47
47
 
@@ -64,17 +64,17 @@ module RSpec
64
64
  return <<-EOF
65
65
  Isn't life confusing enough?
66
66
  Instead of having to figure out the meaning of this:
67
- should_not have_at_most(#{@expected}).#{@collection_name}
67
+ #{Expectations::Syntax.negative_expression("actual", "have_at_most(#{@expected}).#{@collection_name}")}
68
68
  We recommend that you use this instead:
69
- should have_at_least(#{@expected + 1}).#{@collection_name}
69
+ #{Expectations::Syntax.positive_expression("actual", "have_at_least(#{@expected + 1}).#{@collection_name}")}
70
70
  EOF
71
71
  elsif @relativity == :at_least
72
72
  return <<-EOF
73
73
  Isn't life confusing enough?
74
74
  Instead of having to figure out the meaning of this:
75
- should_not have_at_least(#{@expected}).#{@collection_name}
75
+ #{Expectations::Syntax.negative_expression("actual", "have_at_least(#{@expected}).#{@collection_name}")}
76
76
  We recommend that you use this instead:
77
- should have_at_most(#{@expected - 1}).#{@collection_name}
77
+ #{Expectations::Syntax.positive_expression("actual", "have_at_most(#{@expected - 1}).#{@collection_name}")}
78
78
  EOF
79
79
  end
80
80
  end
@@ -21,19 +21,23 @@ module RSpec
21
21
  end
22
22
 
23
23
  def diffable?
24
- true
24
+ # Matchers do not diff well, since diff uses their inspect
25
+ # output, which includes their instance variables and such.
26
+ @expected.none? { |e| is_a_matcher?(e) }
25
27
  end
26
28
 
27
29
  private
28
30
 
29
31
  def perform_match(predicate, hash_predicate, actuals, expecteds)
30
- expecteds.send(predicate) do |expected|
32
+ expecteds.__send__(predicate) do |expected|
31
33
  if comparing_hash_values?(actuals, expected)
32
- expected.send(hash_predicate) {|k,v|
34
+ expected.__send__(hash_predicate) { |k,v|
33
35
  actuals.has_key?(k) && actuals[k] == v
34
36
  }
35
37
  elsif comparing_hash_keys?(actuals, expected)
36
38
  actuals.has_key?(expected)
39
+ elsif comparing_with_matcher?(actual, expected)
40
+ actual.any? { |value| expected.matches?(value) }
37
41
  else
38
42
  actuals.include?(expected)
39
43
  end
@@ -47,6 +51,18 @@ module RSpec
47
51
  def comparing_hash_values?(actual, expected)
48
52
  actual.is_a?(Hash) && expected.is_a?(Hash)
49
53
  end
54
+
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?)
65
+ end
50
66
  end
51
67
  end
52
68
  end
@@ -42,7 +42,7 @@ module RSpec
42
42
 
43
43
  def find_failing_method_names(actual, filter_method)
44
44
  @actual = actual
45
- @failing_method_names = @names.send(filter_method) do |name|
45
+ @failing_method_names = @names.__send__(filter_method) do |name|
46
46
  @actual.respond_to?(name) && matches_arity?(actual, name)
47
47
  end
48
48
  end
@@ -28,7 +28,7 @@ module RSpec
28
28
  Thread.critical = orig_critical
29
29
  end
30
30
  begin
31
- return send(method_name, *args)
31
+ return __send__(method_name, *args)
32
32
  ensure
33
33
  singleton_class.module_eval{ remove_method(method_name) } rescue nil
34
34
  end