rspec-expectations 3.0.0.beta1 → 3.0.0.beta2

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 (122) hide show
  1. data.tar.gz.sig +2 -2
  2. data/.yardopts +1 -0
  3. data/Changelog.md +138 -0
  4. data/README.md +75 -8
  5. data/features/README.md +2 -2
  6. data/features/built_in_matchers/README.md +12 -9
  7. data/features/built_in_matchers/comparisons.feature +2 -2
  8. data/features/built_in_matchers/contain_exactly.feature +46 -0
  9. data/features/built_in_matchers/expect_change.feature +2 -2
  10. data/features/built_in_matchers/include.feature +0 -48
  11. data/features/built_in_matchers/output.feature +70 -0
  12. data/features/composing_matchers.feature +250 -0
  13. data/features/compound_expectations.feature +45 -0
  14. data/features/custom_matchers/access_running_example.feature +1 -1
  15. data/features/custom_matchers/define_matcher.feature +6 -6
  16. data/features/custom_matchers/define_matcher_outside_rspec.feature +4 -8
  17. data/features/test_frameworks/{test_unit.feature → minitest.feature} +11 -11
  18. data/lib/rspec/expectations.rb +31 -42
  19. data/lib/rspec/expectations/diff_presenter.rb +141 -0
  20. data/lib/rspec/expectations/differ.rb +22 -132
  21. data/lib/rspec/expectations/encoded_string.rb +56 -0
  22. data/lib/rspec/expectations/expectation_target.rb +0 -30
  23. data/lib/rspec/expectations/fail_with.rb +2 -2
  24. data/lib/rspec/expectations/handler.rb +128 -31
  25. data/lib/rspec/expectations/minitest_integration.rb +16 -0
  26. data/lib/rspec/expectations/syntax.rb +4 -58
  27. data/lib/rspec/expectations/version.rb +1 -1
  28. data/lib/rspec/matchers.rb +298 -60
  29. data/lib/rspec/matchers/aliased_matcher.rb +35 -0
  30. data/lib/rspec/matchers/built_in.rb +37 -33
  31. data/lib/rspec/matchers/built_in/base_matcher.rb +25 -15
  32. data/lib/rspec/matchers/built_in/be.rb +23 -31
  33. data/lib/rspec/matchers/built_in/be_between.rb +55 -0
  34. data/lib/rspec/matchers/built_in/be_within.rb +15 -11
  35. data/lib/rspec/matchers/built_in/change.rb +198 -81
  36. data/lib/rspec/matchers/built_in/compound.rb +106 -0
  37. data/lib/rspec/matchers/built_in/contain_exactly.rb +245 -0
  38. data/lib/rspec/matchers/built_in/eq.rb +43 -4
  39. data/lib/rspec/matchers/built_in/eql.rb +2 -2
  40. data/lib/rspec/matchers/built_in/equal.rb +35 -18
  41. data/lib/rspec/matchers/built_in/has.rb +16 -15
  42. data/lib/rspec/matchers/built_in/include.rb +45 -23
  43. data/lib/rspec/matchers/built_in/match.rb +6 -3
  44. data/lib/rspec/matchers/built_in/operators.rb +103 -0
  45. data/lib/rspec/matchers/built_in/output.rb +108 -0
  46. data/lib/rspec/matchers/built_in/raise_error.rb +9 -15
  47. data/lib/rspec/matchers/built_in/respond_to.rb +5 -4
  48. data/lib/rspec/matchers/built_in/satisfy.rb +4 -3
  49. data/lib/rspec/matchers/built_in/start_and_end_with.rb +37 -16
  50. data/lib/rspec/matchers/built_in/throw_symbol.rb +6 -5
  51. data/lib/rspec/matchers/built_in/yield.rb +31 -29
  52. data/lib/rspec/matchers/composable.rb +138 -0
  53. data/lib/rspec/matchers/dsl.rb +330 -0
  54. data/lib/rspec/matchers/generated_descriptions.rb +6 -6
  55. data/lib/rspec/matchers/matcher_delegator.rb +33 -0
  56. data/lib/rspec/matchers/pretty.rb +13 -2
  57. data/spec/rspec/expectations/{differ_spec.rb → diff_presenter_spec.rb} +56 -36
  58. data/spec/rspec/expectations/encoded_string_spec.rb +74 -0
  59. data/spec/rspec/expectations/extensions/kernel_spec.rb +11 -11
  60. data/spec/rspec/expectations/fail_with_spec.rb +8 -8
  61. data/spec/rspec/expectations/handler_spec.rb +27 -49
  62. data/spec/rspec/expectations/minitest_integration_spec.rb +27 -0
  63. data/spec/rspec/expectations/syntax_spec.rb +17 -67
  64. data/spec/rspec/expectations_spec.rb +7 -52
  65. data/spec/rspec/matchers/aliased_matcher_spec.rb +48 -0
  66. data/spec/rspec/matchers/aliases_spec.rb +449 -0
  67. data/spec/rspec/matchers/{base_matcher_spec.rb → built_in/base_matcher_spec.rb} +24 -3
  68. data/spec/rspec/matchers/built_in/be_between_spec.rb +159 -0
  69. data/spec/rspec/matchers/{be_instance_of_spec.rb → built_in/be_instance_of_spec.rb} +0 -0
  70. data/spec/rspec/matchers/{be_kind_of_spec.rb → built_in/be_kind_of_spec.rb} +0 -0
  71. data/spec/rspec/matchers/{be_spec.rb → built_in/be_spec.rb} +76 -32
  72. data/spec/rspec/matchers/{be_within_spec.rb → built_in/be_within_spec.rb} +6 -2
  73. data/spec/rspec/matchers/{change_spec.rb → built_in/change_spec.rb} +310 -69
  74. data/spec/rspec/matchers/built_in/compound_spec.rb +292 -0
  75. data/spec/rspec/matchers/built_in/contain_exactly_spec.rb +441 -0
  76. data/spec/rspec/matchers/{cover_spec.rb → built_in/cover_spec.rb} +0 -0
  77. data/spec/rspec/matchers/built_in/eq_spec.rb +156 -0
  78. data/spec/rspec/matchers/{eql_spec.rb → built_in/eql_spec.rb} +2 -2
  79. data/spec/rspec/matchers/built_in/equal_spec.rb +106 -0
  80. data/spec/rspec/matchers/{exist_spec.rb → built_in/exist_spec.rb} +1 -1
  81. data/spec/rspec/matchers/{has_spec.rb → built_in/has_spec.rb} +39 -0
  82. data/spec/rspec/matchers/{include_spec.rb → built_in/include_spec.rb} +118 -109
  83. data/spec/rspec/matchers/{match_spec.rb → built_in/match_spec.rb} +30 -2
  84. data/spec/rspec/matchers/{operator_matcher_spec.rb → built_in/operators_spec.rb} +26 -26
  85. data/spec/rspec/matchers/built_in/output_spec.rb +165 -0
  86. data/spec/rspec/matchers/{raise_error_spec.rb → built_in/raise_error_spec.rb} +81 -11
  87. data/spec/rspec/matchers/{respond_to_spec.rb → built_in/respond_to_spec.rb} +0 -0
  88. data/spec/rspec/matchers/{satisfy_spec.rb → built_in/satisfy_spec.rb} +0 -0
  89. data/spec/rspec/matchers/{start_with_end_with_spec.rb → built_in/start_and_end_with_spec.rb} +82 -15
  90. data/spec/rspec/matchers/{throw_symbol_spec.rb → built_in/throw_symbol_spec.rb} +29 -10
  91. data/spec/rspec/matchers/{yield_spec.rb → built_in/yield_spec.rb} +90 -0
  92. data/spec/rspec/matchers/configuration_spec.rb +7 -39
  93. data/spec/rspec/matchers/description_generation_spec.rb +22 -6
  94. data/spec/rspec/matchers/dsl_spec.rb +838 -0
  95. data/spec/rspec/matchers/legacy_spec.rb +101 -0
  96. data/spec/rspec/matchers_spec.rb +74 -0
  97. data/spec/spec_helper.rb +35 -21
  98. data/spec/support/shared_examples.rb +26 -4
  99. metadata +172 -116
  100. metadata.gz.sig +3 -4
  101. checksums.yaml +0 -15
  102. checksums.yaml.gz.sig +0 -0
  103. data/features/built_in_matchers/match_array.feature +0 -37
  104. data/lib/rspec/expectations/errors.rb +0 -9
  105. data/lib/rspec/expectations/extensions.rb +0 -1
  106. data/lib/rspec/expectations/extensions/object.rb +0 -29
  107. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  108. data/lib/rspec/matchers/compatibility.rb +0 -14
  109. data/lib/rspec/matchers/matcher.rb +0 -301
  110. data/lib/rspec/matchers/method_missing.rb +0 -12
  111. data/lib/rspec/matchers/operator_matcher.rb +0 -99
  112. data/lib/rspec/matchers/test_unit_integration.rb +0 -11
  113. data/spec/rspec/matchers/eq_spec.rb +0 -60
  114. data/spec/rspec/matchers/equal_spec.rb +0 -78
  115. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  116. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  117. data/spec/rspec/matchers/matcher_spec.rb +0 -706
  118. data/spec/rspec/matchers/matchers_spec.rb +0 -36
  119. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  120. data/spec/support/classes.rb +0 -56
  121. data/spec/support/in_sub_process.rb +0 -37
  122. data/spec/support/ruby_version.rb +0 -10
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+ require 'date'
3
+ require 'complex'
4
+
5
+ module RSpec
6
+ module Matchers
7
+ describe "eq" do
8
+ it_behaves_like "an RSpec matcher", :valid_value => 1, :invalid_value => 2 do
9
+ let(:matcher) { eq(1) }
10
+ end
11
+
12
+ it "is diffable" do
13
+ expect(eq(1)).to be_diffable
14
+ end
15
+
16
+ it "matches when actual == expected" do
17
+ expect(1).to eq(1)
18
+ end
19
+
20
+ it "does not match when actual != expected" do
21
+ expect(1).not_to eq(2)
22
+ end
23
+
24
+ it "compares by sending == to actual (not expected)" do
25
+ called = false
26
+ actual = Class.new do
27
+ define_method :== do |other|
28
+ called = true
29
+ end
30
+ end.new
31
+
32
+ expect(actual).to eq :anything # to trigger the matches? method
33
+ expect(called).to be_truthy
34
+ end
35
+
36
+ it "describes itself" do
37
+ matcher = eq(1)
38
+ matcher.matches?(1)
39
+ expect(matcher.description).to eq "eq 1"
40
+ end
41
+
42
+ it "provides message, expected and actual on #failure_message" do
43
+ matcher = eq("1")
44
+ matcher.matches?(1)
45
+ expect(matcher.failure_message).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using ==)\n"
46
+ end
47
+
48
+ it "provides message, expected and actual on #negative_failure_message" do
49
+ matcher = eq(1)
50
+ matcher.matches?(1)
51
+ expect(matcher.failure_message_when_negated).to eq "\nexpected: value != 1\n got: 1\n\n(compared using ==)\n"
52
+ end
53
+
54
+ it 'fails properly when the actual is an array of multiline strings' do
55
+ expect {
56
+ expect(["a\nb", "c\nd"]).to eq([])
57
+ }.to fail_matching("expected: []")
58
+ end
59
+
60
+ describe '#description' do
61
+ [
62
+ [nil, 'eq nil'],
63
+ [true, 'eq true'],
64
+ [false, 'eq false'],
65
+ [:symbol, 'eq :symbol'],
66
+ [1, 'eq 1'],
67
+ [1.2, 'eq 1.2'],
68
+ [Complex(1, 2), "eq #{Complex(1, 2).inspect}"],
69
+ ['foo', 'eq "foo"'],
70
+ [/regex/, 'eq /regex/'],
71
+ [['foo'], 'eq ["foo"]'],
72
+ [{:foo => :bar}, 'eq {:foo=>:bar}'],
73
+ [Class, 'eq Class'],
74
+ [RSpec, 'eq RSpec'],
75
+ [Date.new(2014, 1, 1), "eq #{Date.new(2014, 1, 1).inspect}"],
76
+ [Time.utc(2014, 1, 1), "eq #{Time.utc(2014, 1, 1).inspect}"],
77
+ ].each do |expected, expected_description|
78
+ context "with #{expected.inspect}" do
79
+ it "is \"#{expected_description}\"" do
80
+ expect(eq(expected).description).to eq expected_description
81
+ end
82
+ end
83
+ end
84
+
85
+ context 'with object' do
86
+ it 'matches with "^eq #<Object:0x[0-9a-f]*>$"' do
87
+ expect(eq(Object.new).description).to match(/^eq #<Object:0x[0-9a-f]*>$/)
88
+ end
89
+ end
90
+ end
91
+
92
+ context "Time Equality" do
93
+ RSpec::Matchers.define :a_string_with_differing_output do
94
+ match do |string|
95
+ time_strings = /expected: (.+)\n.*got: (.+)$/.match(string).captures
96
+ time_strings.uniq.count == 2
97
+ end
98
+ end
99
+
100
+ RSpec::Matchers.define :a_string_with_identical_output do
101
+ match do |string|
102
+ time_strings = /expected: value != (.+)\n.*got: (.+)$/.match(string).captures
103
+ time_strings.uniq.count == 1
104
+ end
105
+ end
106
+
107
+ context 'with Time objects' do
108
+ let(:time1) { Time.utc(1969, 12, 31, 19, 01, 40, 101) }
109
+ let(:time2) { Time.utc(1969, 12, 31, 19, 01, 40, 102) }
110
+
111
+ it 'produces different output for Times differing by milliseconds' do
112
+ expect {
113
+ expect(time1).to eq(time2)
114
+ }.to fail_with(a_string_with_differing_output)
115
+ end
116
+ end
117
+
118
+ context 'with DateTime objects' do
119
+ let(:date1) { DateTime.new(2000, 1, 1, 1, 1, Rational(1, 10)) }
120
+ let(:date2) { DateTime.new(2000, 1, 1, 1, 1, Rational(2, 10)) }
121
+
122
+ it 'produces different output for DateTimes differing by milliseconds' do
123
+ expect {
124
+ expect(date1).to eq(date2)
125
+ }.to fail_with(a_string_with_differing_output)
126
+ end
127
+
128
+ it 'does not not assume DateTime is defined since you need to require `date` to make it available' do
129
+ hide_const('DateTime')
130
+ expect {
131
+ expect(5).to eq(4)
132
+ }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
133
+ end
134
+
135
+ it 'fails with identical output when the DateTimes are exactly the same' do
136
+ expect {
137
+ expect(date1).to_not eq(date1)
138
+ }.to fail_with(a_string_with_identical_output)
139
+ end
140
+
141
+ context 'when ActiveSupport is loaded' do
142
+ it "uses a custom format to ensure the output is different when DateTimes differ" do
143
+ stub_const("ActiveSupport", Module.new)
144
+ allow(date1).to receive(:inspect).and_return("Timestamp")
145
+ allow(date2).to receive(:inspect).and_return("Timestamp")
146
+
147
+ expect {
148
+ expect(date1).to eq(date2)
149
+ }.to fail_with(a_string_with_differing_output)
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -28,13 +28,13 @@ module RSpec
28
28
  it "provides message, expected and actual on #failure_message" do
29
29
  matcher = eql("1")
30
30
  matcher.matches?(1)
31
- expect(matcher.failure_message_for_should).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using eql?)\n"
31
+ expect(matcher.failure_message).to eq "\nexpected: \"1\"\n got: 1\n\n(compared using eql?)\n"
32
32
  end
33
33
 
34
34
  it "provides message, expected and actual on #negative_failure_message" do
35
35
  matcher = eql(1)
36
36
  matcher.matches?(1)
37
- expect(matcher.failure_message_for_should_not).to eq "\nexpected: value != 1\n got: 1\n\n(compared using eql?)\n"
37
+ expect(matcher.failure_message_when_negated).to eq "\nexpected: value != 1\n got: 1\n\n(compared using eql?)\n"
38
38
  end
39
39
  end
40
40
  end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+ module RSpec
3
+ module Matchers
4
+ describe "equal" do
5
+ it_behaves_like "an RSpec matcher", :valid_value => :a, :invalid_value => :b do
6
+ let(:matcher) { equal(:a) }
7
+ end
8
+
9
+ def inspect_object(o)
10
+ "#<#{o.class}:#{o.object_id}> => #{o.inspect}"
11
+ end
12
+
13
+ it "matches when actual.equal?(expected)" do
14
+ expect(1).to equal(1)
15
+ end
16
+
17
+ it "does not match when !actual.equal?(expected)" do
18
+ expect("1").not_to equal("1")
19
+ end
20
+
21
+ it "describes itself" do
22
+ matcher = equal(1)
23
+ matcher.matches?(1)
24
+ expect(matcher.description).to eq "equal 1"
25
+ end
26
+
27
+ context "when the expected object is falsey in conditinal semantics" do
28
+ it "describes itself with the expected object" do
29
+ matcher = equal(nil)
30
+ matcher.matches?(nil)
31
+ expect(matcher.description).to eq "equal nil"
32
+ end
33
+ end
34
+
35
+ context "when the expected object's #equal? always returns true" do
36
+ let(:strange_string) do
37
+ string = "foo"
38
+
39
+ def string.equal?(other)
40
+ true
41
+ end
42
+
43
+ string
44
+ end
45
+
46
+ it "describes itself with the expected object" do
47
+ matcher = equal(strange_string)
48
+ matcher.matches?(strange_string)
49
+ expect(matcher.description).to eq 'equal "foo"'
50
+ end
51
+ end
52
+
53
+ it "prints a special message for `false`" do
54
+ expected, actual = false, "1"
55
+ expect {
56
+ expect(actual).to equal(expected)
57
+ }.to fail_with "\nexpected false\n got #{inspect_object(actual)}\n"
58
+ end
59
+
60
+ it "prints a special message for `true`" do
61
+ expected, actual = true, "1"
62
+ expect {
63
+ expect(actual).to equal(expected)
64
+ }.to fail_with "\nexpected true\n got #{inspect_object(actual)}\n"
65
+ end
66
+
67
+ it "prints a special message for `nil`" do
68
+ expected, actual = nil, "1"
69
+ expect {
70
+ expect(actual).to equal(expected)
71
+ }.to fail_with "\nexpected nil\n got #{inspect_object(actual)}\n"
72
+ end
73
+
74
+ it "suggests the `eq` matcher on failure" do
75
+ expected, actual = "1", "1"
76
+ expect {
77
+ expect(actual).to equal(expected)
78
+ }.to fail_with <<-MESSAGE
79
+
80
+ expected #{inspect_object(expected)}
81
+ got #{inspect_object(actual)}
82
+
83
+ Compared using equal?, which compares object identity,
84
+ but expected and actual are not the same object. Use
85
+ `expect(actual).to eq(expected)` if you don't care about
86
+ object identity in this example.
87
+
88
+ MESSAGE
89
+ end
90
+
91
+ it "provides message on #negative_failure_message" do
92
+ expected = actual = "1"
93
+ matcher = equal(expected)
94
+ matcher.matches?(actual)
95
+ expect(matcher.failure_message_when_negated).to eq <<-MESSAGE
96
+
97
+ expected not #{inspect_object(expected)}
98
+ got #{inspect_object(actual)}
99
+
100
+ Compared using equal?, which compares object identity.
101
+
102
+ MESSAGE
103
+ end
104
+ end
105
+ end
106
+ end
@@ -117,7 +117,7 @@ describe "exist matcher" do
117
117
 
118
118
  it 'passes any provided arguments to the call to #exist?' do
119
119
  object = double
120
- object.should_receive(:exist?).with(:foo, :bar) { true }
120
+ expect(object).to receive(:exist?).with(:foo, :bar) { true }
121
121
 
122
122
  expect(object).to exist(:foo, :bar)
123
123
  end
@@ -16,6 +16,34 @@ describe "expect(...).to have_sym(*args)" do
16
16
  }.to fail_with("expected #has_key?(:a) to return true, got false")
17
17
  end
18
18
 
19
+ obj_with_block_method = Object.new
20
+ def obj_with_block_method.has_some_stuff?; yield; end
21
+
22
+ it 'forwards the given `{ }` block on to the `has_xyz?` method' do
23
+ expect(obj_with_block_method).to have_some_stuff { true }
24
+ expect(obj_with_block_method).to_not have_some_stuff { false }
25
+ end
26
+
27
+ it 'forwards the given `do..end` block on to the `has_xyz?` method' do
28
+ expect(obj_with_block_method).to have_some_stuff do
29
+ true
30
+ end
31
+
32
+ expect(obj_with_block_method).to_not have_some_stuff do
33
+ false
34
+ end
35
+ end
36
+
37
+ it 'favors a curly brace block over a do...end one since it binds to the matcher method' do
38
+ expect(obj_with_block_method).to have_some_stuff { true } do
39
+ false
40
+ end
41
+
42
+ expect(obj_with_block_method).not_to have_some_stuff { false } do
43
+ true
44
+ end
45
+ end
46
+
19
47
  it 'does not include any args in the failure message if no args were given to the matcher' do
20
48
  o = Object.new
21
49
  def o.has_some_stuff?; false; end
@@ -57,6 +85,17 @@ describe "expect(...).to have_sym(*args)" do
57
85
  expect(o).to have_sym(:foo)
58
86
  }.to raise_error("Funky exception")
59
87
  end
88
+
89
+ it 'allows composable aliases to be defined' do
90
+ RSpec::Matchers.alias_matcher :an_object_having_sym, :have_sym
91
+ o = Object.new
92
+ def o.has_sym?(sym); sym == :foo; end
93
+
94
+ expect(o).to an_object_having_sym(:foo)
95
+ expect(o).not_to an_object_having_sym(:bar)
96
+
97
+ expect(an_object_having_sym(:foo).description).to eq("an object having sym :foo")
98
+ end
60
99
  end
61
100
 
62
101
  describe "expect(...).not_to have_sym(*args)" do
@@ -69,13 +69,13 @@ describe "#include matcher" do
69
69
  it "fails if target does not include expected" do
70
70
  expect {
71
71
  expect({:key => 'value'}).to include(:other)
72
- }.to fail_matching(%Q|expected {:key=>"value"} to include :other|)
72
+ }.to fail_matching(%Q|expected {:key => "value"} to include :other|)
73
73
  end
74
74
 
75
75
  it "fails if target doesn't have a key and we expect nil" do
76
76
  expect {
77
77
  expect({}).to include(:something => nil)
78
- }.to fail_matching(%Q|expected {} to include {:something=>nil}|)
78
+ }.to fail_matching(%Q|expected {} to include {:something => nil}|)
79
79
  end
80
80
 
81
81
  it 'works even when an entry in the hash overrides #send' do
@@ -132,7 +132,7 @@ describe "#include matcher" do
132
132
  it 'fails if target is missing any item as a key' do
133
133
  expect {
134
134
  expect({:key => 'value'}).to include(:key, :other)
135
- }.to fail_matching(%Q|expected {:key=>"value"} to include :key and :other|)
135
+ }.to fail_matching(%Q|expected {:key => "value"} to include :key and :other|)
136
136
  end
137
137
  end
138
138
  end
@@ -182,7 +182,7 @@ describe "#include matcher" do
182
182
  it "fails if target includes expected key" do
183
183
  expect {
184
184
  expect({:key => 'value'}).not_to include(:key)
185
- }.to fail_matching(%Q|expected {:key=>"value"} not to include :key|)
185
+ }.to fail_matching(%Q|expected {:key => "value"} not to include :key|)
186
186
  end
187
187
  end
188
188
 
@@ -215,13 +215,13 @@ describe "#include matcher" do
215
215
  it "fails if the target includes all of the expected keys" do
216
216
  expect {
217
217
  expect({ :a => 1, :b => 2 }).not_to include(:a, :b)
218
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>2}.inspect} not to include :a and :b|)
218
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 2} not to include :a and :b|)
219
219
  end
220
220
 
221
221
  it "fails if the target includes some (but not all) of the expected keys" do
222
222
  expect {
223
223
  expect({ :a => 1, :b => 2 }).not_to include(:d, :b)
224
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>2}.inspect} not to include :d and :b|)
224
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 2} not to include :d and :b|)
225
225
  end
226
226
  end
227
227
 
@@ -257,13 +257,13 @@ describe "#include matcher" do
257
257
  it "fails if target has a different value for key" do
258
258
  expect {
259
259
  expect({:key => 'different'}).to include(:key => 'value')
260
- }.to fail_matching(%Q|expected {:key=>"different"} to include {:key=>"value"}|)
260
+ }.to fail_matching(%Q|expected {:key => "different"} to include {:key => "value"}|)
261
261
  end
262
262
 
263
263
  it "fails if target has a different key" do
264
264
  expect {
265
265
  expect({:other => 'value'}).to include(:key => 'value')
266
- }.to fail_matching(%Q|expected {:other=>"value"} to include {:key=>"value"}|)
266
+ }.to fail_matching(%Q|expected {:other => "value"} to include {:key => "value"}|)
267
267
  end
268
268
  end
269
269
 
@@ -271,7 +271,7 @@ describe "#include matcher" do
271
271
  it "fails if the target does not contain the given hash" do
272
272
  expect {
273
273
  expect(['a', 'b']).to include(:key => 'value')
274
- }.to fail_matching(%q|expected ["a", "b"] to include {:key=>"value"}|)
274
+ }.to fail_matching(%q|expected ["a", "b"] to include {:key => "value"}|)
275
275
  end
276
276
 
277
277
  it "passes if the target contains the given hash" do
@@ -285,13 +285,13 @@ describe "#include matcher" do
285
285
  it "fails if target includes the key/value pair" do
286
286
  expect {
287
287
  expect({:key => 'value'}).not_to include(:key => 'value')
288
- }.to fail_matching(%Q|expected {:key=>"value"} not to include {:key=>"value"}|)
288
+ }.to fail_matching(%Q|expected {:key => "value"} not to include {:key => "value"}|)
289
289
  end
290
290
 
291
291
  it "fails if target includes the key/value pair among others" do
292
292
  expect {
293
293
  expect({:key => 'value', :other => 'different'}).not_to include(:key => 'value')
294
- }.to fail_matching(%Q|expected #{{:key=>"value", :other=>"different"}.inspect} not to include {:key=>"value"}|)
294
+ }.to fail_matching(%Q|expected #{hash_inspect :key => "value", :other => "different"} not to include {:key => "value"}|)
295
295
  end
296
296
 
297
297
  it "passes if target has a different value for key" do
@@ -311,7 +311,7 @@ describe "#include matcher" do
311
311
  it "fails if the target contains the given hash" do
312
312
  expect {
313
313
  expect(['a', { :key => 'value' } ]).not_to include(:key => 'value')
314
- }.to fail_matching(%Q|expected ["a", {:key=>"value"}] not to include {:key=>"value"}|)
314
+ }.to fail_matching(%Q|expected ["a", {:key => "value"}] not to include {:key => "value"}|)
315
315
  end
316
316
  end
317
317
  end
@@ -329,25 +329,25 @@ describe "#include matcher" do
329
329
  it "fails if target has a different value for one of the keys" do
330
330
  expect {
331
331
  expect({:a => 1, :b => 2}).to include(:a => 2, :b => 2)
332
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>2}.inspect} to include #{{:a=>2, :b=>2}.inspect}|)
332
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 2} to include #{hash_inspect :a => 2, :b => 2}|)
333
333
  end
334
334
 
335
335
  it "fails if target has a different value for both of the keys" do
336
336
  expect {
337
337
  expect({:a => 1, :b => 1}).to include(:a => 2, :b => 2)
338
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>1}.inspect} to include #{{:a=>2, :b=>2}.inspect}|)
338
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 1} to include #{hash_inspect :a => 2, :b => 2}|)
339
339
  end
340
340
 
341
341
  it "fails if target lacks one of the keys" do
342
342
  expect {
343
343
  expect({:a => 1, :b => 1}).to include(:a => 1, :c => 1)
344
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>1}.inspect} to include #{{:a=>1, :c=>1}.inspect}|)
344
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 1} to include #{hash_inspect :a => 1, :c => 1}|)
345
345
  end
346
346
 
347
347
  it "fails if target lacks both of the keys" do
348
348
  expect {
349
349
  expect({:a => 1, :b => 1}).to include(:c => 1, :d => 1)
350
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>1}.inspect} to include #{{:c=>1, :d=>1}.inspect}|)
350
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 1} to include #{hash_inspect :c => 1, :d => 1}|)
351
351
  end
352
352
  end
353
353
 
@@ -355,7 +355,7 @@ describe "#include matcher" do
355
355
  it "fails if the target does not contain the given hash" do
356
356
  expect {
357
357
  expect(['a', 'b']).to include(:a => 1, :b => 1)
358
- }.to fail_matching(%Q|expected ["a", "b"] to include #{{:a=>1, :b=>1}.inspect}|)
358
+ }.to fail_matching(%Q|expected ["a", "b"] to include #{hash_inspect :a => 1, :b => 1}|)
359
359
  end
360
360
 
361
361
  it "passes if the target contains the given hash" do
@@ -369,20 +369,20 @@ describe "#include matcher" do
369
369
  it "fails if target includes the key/value pairs" do
370
370
  expect {
371
371
  expect({:a => 1, :b => 2}).not_to include(:a => 1, :b => 2)
372
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>2}.inspect} not to include #{{:a=>1, :b=>2}.inspect}|)
372
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 2} not to include #{hash_inspect :a => 1, :b => 2}|)
373
373
  end
374
374
 
375
375
  it "fails if target includes the key/value pairs among others" do
376
376
  hash = {:a => 1, :b => 2, :c => 3}
377
377
  expect {
378
378
  expect(hash).not_to include(:a => 1, :b => 2)
379
- }.to fail_matching(%Q|expected #{hash.inspect} not to include #{{:a=>1, :b=>2}.inspect}|)
379
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 2, :c => 3} not to include #{hash_inspect :a => 1, :b => 2}|)
380
380
  end
381
381
 
382
382
  it "fails if target has a different value for one of the keys" do
383
383
  expect {
384
384
  expect({:a => 1, :b => 2}).not_to include(:a => 2, :b => 2)
385
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>2}.inspect} not to include #{{:a=>2, :b=>2}.inspect}|)
385
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 2} not to include #{hash_inspect :a => 2, :b => 2}|)
386
386
  end
387
387
 
388
388
  it "passes if target has a different value for both of the keys" do
@@ -392,7 +392,7 @@ describe "#include matcher" do
392
392
  it "fails if target lacks one of the keys" do
393
393
  expect {
394
394
  expect({:a => 1, :b => 1}).not_to include(:a => 1, :c => 1)
395
- }.to fail_matching(%Q|expected #{{:a=>1, :b=>1}.inspect} not to include #{{:a=>1, :c=>1}.inspect}|)
395
+ }.to fail_matching(%Q|expected #{hash_inspect :a => 1, :b => 1} not to include #{hash_inspect :a => 1, :c => 1}|)
396
396
  end
397
397
 
398
398
  it "passes if target lacks both of the keys" do
@@ -408,124 +408,133 @@ describe "#include matcher" do
408
408
  it "fails if the target contains the given hash" do
409
409
  expect {
410
410
  expect(['a', { :a => 1, :b => 2 } ]).not_to include(:a => 1, :b => 2)
411
- }.to fail_matching(%Q|expected #{["a", {:a=>1, :b=>2}].inspect} not to include #{{:a=>1, :b=>2}.inspect}|)
411
+ }.to fail_matching(%Q|expected ["a", #{hash_inspect :a => 1, :b => 2}] not to include #{hash_inspect :a => 1, :b => 2}|)
412
412
  end
413
413
  end
414
414
  end
415
- end
416
-
417
- RSpec::Matchers.define :a_string_containing do |expected|
418
- match do |actual|
419
- actual.include?(expected)
420
- end
421
415
 
422
- description do
423
- "a string containing '#{expected}'"
424
- end
425
- end
416
+ describe "Composing matchers with `include`" do
417
+ RSpec::Matchers.define :a_string_containing do |expected|
418
+ match do |actual|
419
+ actual.include?(expected)
420
+ end
426
421
 
427
- describe "expect(...).to include(matcher)" do
428
- context 'for an array target' do
429
- it "passes if target includes an object that satisfies the matcher" do
430
- expect(['foo', 'bar', 'baz']).to include(a_string_containing("ar"))
422
+ description do
423
+ "a string containing '#{expected}'"
424
+ end
431
425
  end
432
426
 
433
- it "fails if target doesn't include object that satisfies the matcher" do
434
- expect {
435
- expect(['foo', 'bar', 'baz']).to include(a_string_containing("abc"))
436
- }.to fail_matching(%Q|expected #{['foo', 'bar', 'baz'].inspect} to include a string containing 'abc'|)
437
- end
427
+ describe "expect(array).to include(matcher)" do
428
+ it "passes when the matcher matches one of the values" do
429
+ expect([10, 20, 30]).to include( a_value_within(5).of(24) )
430
+ end
438
431
 
439
- it 'does not include a diff when the match fails' do
440
- expect {
441
- expect(['foo', 'bar', 'baz']).to include(a_string_containing("abc"))
442
- }.to raise_error { |e|
443
- expect(e.message).not_to match(/diff/i)
444
- }
445
- end
432
+ it 'provides a description' do
433
+ description = include( a_value_within(5).of(24) ).description
434
+ expect(description).to eq("include (a value within 5 of 24)")
435
+ end
446
436
 
447
- it 'does not treat an object that only implements #matches? as a matcher' do
448
- domain = Struct.new(:domain) do
449
- def matches?(url)
450
- URI(url).host == self.domain
451
- end
437
+ it 'fails with a clear message when the matcher matches none of the values' do
438
+ expect {
439
+ expect([10, 30]).to include( a_value_within(5).of(24) )
440
+ }.to fail_with("expected [10, 30] to include (a value within 5 of 24)")
452
441
  end
453
442
 
454
- expect([domain.new("rspec.info")]).to include(domain.new("rspec.info"))
443
+ it 'works with comparison matchers' do
444
+ expect {
445
+ expect([100, 200]).to include(a_value < 90)
446
+ }.to fail_with("expected [100, 200] to include (a value < 90)")
455
447
 
456
- expect {
457
- expect([domain.new("rspec.info")]).to include(domain.new("foo.com"))
458
- }.to fail_matching("expected [#{domain.new("rspec.info").inspect}] to include")
459
- end
448
+ expect([100, 200]).to include(a_value > 150)
449
+ end
460
450
 
461
- it 'works with an old-style matcher that implements failure_message rather than failure_message_for_should' do
462
- a_multiple_of = Class.new do
463
- def initialize(expected)
464
- @expected = expected
451
+ it 'does not treat an object that only implements #matches? as a matcher' do
452
+ domain = Struct.new(:domain) do
453
+ def matches?(url)
454
+ URI(url).host == self.domain
455
+ end
465
456
  end
466
457
 
467
- def matches?(actual)
468
- (actual % @expected).zero?
469
- end
458
+ expect([domain.new("rspec.info")]).to include(domain.new("rspec.info"))
470
459
 
471
- def failure_message
472
- "expected a multiple of #{@expected}"
473
- end
460
+ expect {
461
+ expect([domain.new("rspec.info")]).to include(domain.new("foo.com"))
462
+ }.to fail_matching("expected [#{domain.new("rspec.info").inspect}] to include")
474
463
  end
464
+ end
475
465
 
476
- # Verify the matcher works normally
477
- expect(10).to a_multiple_of.new(5)
466
+ describe "expect(array).to include(multiple, matcher, arguments)" do
467
+ it "passes if target includes items satisfying all matchers" do
468
+ expect(['foo', 'bar', 'baz']).to include(a_string_containing("ar"), a_string_containing('oo'))
469
+ end
478
470
 
479
- expect {
480
- expect(10).to a_multiple_of.new(7)
481
- }.to fail_with("expected a multiple of 7")
471
+ it "fails if target does not include an item satisfying any one of the items" do
472
+ expect {
473
+ expect(['foo', 'bar', 'baz']).to include(a_string_containing("ar"), a_string_containing("abc"))
474
+ }.to fail_matching(%Q|expected #{['foo', 'bar', 'baz'].inspect} to include (a string containing 'ar') and (a string containing 'abc')|)
475
+ end
476
+ end
482
477
 
483
- expect([12, 13, 14]).to include(a_multiple_of.new(6))
478
+ describe "expect(hash).to include(key => matcher)" do
479
+ it "passes when the matcher matches" do
480
+ expect(:a => 12).to include(:a => a_value_within(3).of(10))
481
+ end
484
482
 
485
- expect {
486
- expect([12, 13, 14]).to include(a_multiple_of.new(10))
487
- }.to fail_matching("expected [12, 13, 14] to include")
488
- end
489
- end
490
- end
483
+ it 'provides a description' do
484
+ description = include(:a => a_value_within(3).of(10)).description
485
+ expect(description).to eq("include {:a => (a value within 3 of 10)}")
486
+ end
491
487
 
492
- describe "expect(...).to include(multiple, matcher, arguments)" do
493
- context 'for an array target' do
494
- it "passes if target includes items satisfying all matchers" do
495
- expect(['foo', 'bar', 'baz']).to include(a_string_containing("ar"), a_string_containing('oo'))
488
+ it "fails with a clear message when the matcher does not match" do
489
+ expect {
490
+ expect(:a => 15).to include(:a => a_value_within(3).of(10))
491
+ }.to fail_matching("expected {:a => 15} to include {:a => (a value within 3 of 10)}")
492
+ end
496
493
  end
497
494
 
498
- it "fails if target does not include an item satisfying any one of the items" do
499
- expect {
500
- expect(['foo', 'bar', 'baz']).to include(a_string_containing("ar"), a_string_containing("abc"))
501
- }.to fail_matching(%Q|expected #{['foo', 'bar', 'baz'].inspect} to include a string containing 'ar' and a string containing 'abc'|)
502
- end
495
+ describe "expect(hash).to include(key_matcher)" do
496
+ it "passes when the matcher matches a key", :if => (RUBY_VERSION.to_f > 1.8) do
497
+ expect(:drink => "water", :food => "bread").to include(a_string_matching(/foo/))
498
+ end
503
499
 
504
- it 'does not include a diff when the match fails' do
505
- expect {
506
- expect(['foo', 'bar', 'baz']).to include(a_string_containing("ar"), a_string_containing("abc"))
507
- }.to raise_error { |e|
508
- expect(e.message).not_to match(/diff/i)
509
- }
500
+ it 'provides a description' do
501
+ description = include(a_string_matching(/foo/)).description
502
+ expect(description).to eq("include (a string matching /foo/)")
503
+ end
504
+
505
+ it 'fails with a clear message when the matcher does not match', :if => (RUBY_VERSION.to_f > 1.8) do
506
+ expect {
507
+ expect(:drink => "water", :food => "bread").to include(a_string_matching(/bar/))
508
+ }.to fail_matching('expected {:drink => "water", :food => "bread"} to include (a string matching /bar/)')
509
+ end
510
510
  end
511
- end
512
- end
513
511
 
514
- describe "expect(...).not_to include(multiple, matcher, arguments)" do
515
- it "passes if none of the target values satisfies any of the matchers" do
516
- expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("gh"), a_string_containing('de'))
517
- end
512
+ describe "expect(array).not_to include(multiple, matcher, arguments)" do
513
+ it "passes if none of the target values satisfies any of the matchers" do
514
+ expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("gh"), a_string_containing('de'))
515
+ end
518
516
 
519
- it 'fails if all of the matchers are satisfied by one of the target values' do
520
- expect {
521
- expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("ar"), a_string_containing('az'))
522
- }.to fail_matching(%Q|expected #{['foo', 'bar', 'baz'].inspect} not to include a string containing 'ar' and a string containing 'az'|)
517
+ it 'fails if all of the matchers are satisfied by one of the target values' do
518
+ expect {
519
+ expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("ar"), a_string_containing('az'))
520
+ }.to fail_matching(%Q|expected #{['foo', 'bar', 'baz'].inspect} not to include (a string containing 'ar') and (a string containing 'az')|)
521
+ end
522
+
523
+ it 'fails if the some (but not all) of the matchers are satisifed' do
524
+ expect {
525
+ expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("ar"), a_string_containing('bz'))
526
+ }.to fail_matching(%Q|expected #{['foo', 'bar', 'baz'].inspect} not to include (a string containing 'ar') and (a string containing 'bz')|)
527
+ end
528
+ end
523
529
  end
524
530
 
525
- it 'fails if the some (but not all) of the matchers are satisifed' do
526
- expect {
527
- expect(['foo', 'bar', 'baz']).not_to include(a_string_containing("ar"), a_string_containing('bz'))
528
- }.to fail_matching(%Q|expected #{['foo', 'bar', 'baz'].inspect} not to include a string containing 'ar' and a string containing 'bz'|)
531
+ include RSpec::Matchers::Pretty
532
+ # We have to use Hash#inspect in examples that have multi-entry
533
+ # hashes because the #inspect output on 1.8.7 is non-deterministic
534
+ # due to the fact that hashes are not ordered. So we can't simply
535
+ # put a literal string for what we expect because it varies.
536
+ def hash_inspect(hash)
537
+ improve_hash_formatting(hash.inspect)
529
538
  end
530
539
  end
531
540