Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit 1c7096f

Browse files
committed
Merge pull request #1597 from rspec/fix-ruby-head
Relax specs for Ruby 3.4 hash formatting
1 parent 0d6a023 commit 1c7096f

File tree

9 files changed

+124
-51
lines changed

9 files changed

+124
-51
lines changed

Diff for: features/setting_constraints/matching_arguments.feature

+3-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Feature: Matching arguments
7373
end
7474
"""
7575
When I run `rspec keyword_example_spec.rb`
76-
Then it should fail with the following output:
76+
Then it should fail with the following output, ignoring hash syntax:
7777
| 2 examples, 1 failure |
7878
| |
7979
| Failure/Error: dbl.foo(bar: "incorrect") |
@@ -100,7 +100,7 @@ Feature: Matching arguments
100100
end
101101
"""
102102
When I run `rspec keyword_example_spec.rb`
103-
Then it should fail with the following output:
103+
Then it should fail with the following output, ignoring hash syntax:
104104
| 1 example, 1 failure |
105105
| |
106106
| Failure/Error: dbl.foo({bar: "also incorrect"}) |
@@ -156,7 +156,7 @@ Feature: Matching arguments
156156
end
157157
"""
158158
When I run `rspec rspec_satisfy_spec.rb`
159-
Then it should fail with the following output:
159+
Then it should fail with the following output, ignoring hash syntax:
160160
| 2 examples, 1 failure |
161161
| |
162162
| Failure/Error: dbl.foo({ :a => { :b => { :c => 3 } } }) |

Diff for: features/step_definitions/additional_cli_steps.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@
2222
diffable
2323
end
2424

25-
Then /^it should fail with the following output:$/ do |table|
25+
Then /^it should fail with the following output(, ignoring hash syntax)?:$/ do |ignore_hash_syntax, table|
2626
step %q(the exit status should be 1)
2727
lines = table.raw.flatten.reject(&:empty?)
28+
29+
if ignore_hash_syntax && RUBY_VERSION.to_f > 3.3
30+
lines = lines.map { |line| line.gsub(/([^\s])=>/, '\1 => ') }
31+
end
32+
2833
expect(all_output).to match_table(lines)
2934
end

Diff for: spec/rspec/mocks/argument_matchers_spec.rb

+9-5
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ module Mocks
256256
expect(a_double).to receive(:random_call).with(hash_including(:a => 1))
257257
expect {
258258
a_double.random_call(:a => 2)
259-
}.to fail_including "expected: (hash_including(:a=>1))"
259+
}.to fail_including "expected: (hash_including(#{hash_syntax(:a => 1)}))"
260260
end
261261
end
262262

@@ -270,7 +270,7 @@ module Mocks
270270
expect(a_double).to receive(:random_call).with(hash_excluding(:a => 1))
271271
expect {
272272
a_double.random_call(:a => 1)
273-
}.to fail_including "expected: (hash_not_including(:a=>1))"
273+
}.to fail_including "expected: (hash_not_including(#{hash_syntax(:a => 1)}))"
274274
end
275275
end
276276

@@ -431,7 +431,7 @@ def ==(other)
431431
expect(a_double).to receive(:random_call).with(:a => "a", :b => "b")
432432
expect do
433433
a_double.random_call(opts)
434-
end.to fail_with(/expected: \(\{(:a=>\"a\", :b=>\"b\"|:b=>\"b\", :a=>\"a\")\}\)/)
434+
end.to fail_with(/expected: \(\{(:a\s*=>\s*\"a\", :b\s*=>\s*\"b\"|:b\s*=>\s*\"b\", :a\s*=>\s*\"a\")\}\)/)
435435
end
436436
else
437437
it "matches against a hash submitted as a positional argument and received as keyword arguments in Ruby 2.7 or before" do
@@ -445,14 +445,14 @@ def ==(other)
445445
expect(a_double).to receive(:random_call).with(:a => "b", :c => "d")
446446
expect do
447447
a_double.random_call(:a => "b", :c => "e")
448-
end.to fail_with(/expected: \(\{(:a=>\"b\", :c=>\"d\"|:c=>\"d\", :a=>\"b\")\}\)/)
448+
end.to fail_with(/expected: \(\{(:a\s*=>\s*\"b\", :c\s*=>\s*\"d\"|:c\s*=>\s*\"d\", :a\s*=>\s*\"b\")\}\)/)
449449
end
450450

451451
it "fails for a hash w/ wrong keys", :reset => true do
452452
expect(a_double).to receive(:random_call).with(:a => "b", :c => "d")
453453
expect do
454454
a_double.random_call("a" => "b", "c" => "d")
455-
end.to fail_with(/expected: \(\{(:a=>\"b\", :c=>\"d\"|:c=>\"d\", :a=>\"b\")\}\)/)
455+
end.to fail_with(/expected: \(\{(:a\s*=>\s*\"b\", :c\s*=>\s*\"d\"|:c\s*=>\s*\"d\", :a\s*=>\s*\"b\")\}\)/)
456456
end
457457

458458
it "matches a class against itself" do
@@ -502,6 +502,10 @@ def ==(other)
502502
expect { a_double.msg 3 }.to fail_including "expected: (my_thing)"
503503
end
504504
end
505+
506+
def hash_syntax(hash)
507+
hash.inspect.gsub(/\{(.*)\}/, '\1')
508+
end
505509
end
506510
end
507511
end

Diff for: spec/rspec/mocks/diffing_spec.rb

+54-30
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,18 @@
100100
if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash?
101101
eval <<-'RUBY', nil, __FILE__, __LINE__ + 1
102102
it "prints a diff when keyword argument were expected but got an option hash (using splat)" do
103+
message =
104+
"#<Double \"double\"> received :foo with unexpected arguments\n" \
105+
" expected: ({:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \
106+
" got: ({:baz=>:quz, :foo=>:bar}) (options hash)"
107+
108+
message = message.gsub('=>', ' => ') if RUBY_VERSION.to_f > 3.3
109+
103110
with_unfulfilled_double do |d|
104111
expect(d).to receive(:foo).with(**expected_hash)
105112
expect {
106113
d.foo(expected_hash)
107-
}.to fail_with(
108-
"#<Double \"double\"> received :foo with unexpected arguments\n" \
109-
" expected: ({:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \
110-
" got: ({:baz=>:quz, :foo=>:bar}) (options hash)"
111-
)
114+
}.to fail_with(message)
112115
end
113116
end
114117
RUBY
@@ -117,14 +120,18 @@
117120
it "prints a diff when keyword argument were expected but got an option hash (literal)" do
118121
with_unfulfilled_double do |d|
119122
expect(d).to receive(:foo).with(:positional, keyword: 1)
120-
expect {
121-
options = { keyword: 1 }
122-
d.foo(:positional, options)
123-
}.to fail_with(
123+
124+
message =
124125
"#<Double \"double\"> received :foo with unexpected arguments\n" \
125126
" expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \
126127
" got: (:positional, {:keyword=>1}) (options hash)"
127-
)
128+
129+
message = message.gsub('=>',' => ') if RUBY_VERSION.to_f > 3.3
130+
131+
expect {
132+
options = { keyword: 1 }
133+
d.foo(:positional, options)
134+
}.to fail_with(message)
128135
end
129136
end
130137
RUBY
@@ -139,18 +146,21 @@
139146
140147
expect(d).to receive(:foo).with(expected_input, one: 1)
141148
142-
expect {
143-
options = { one: 1 }
144-
d.foo(actual_input, options)
145-
}.to fail_with(
149+
message =
146150
"#<Double \"double\"> received :foo with unexpected arguments\n" \
147151
" expected: (#{expected_input.inspect}, {:one=>1}) (keyword arguments)\n" \
148152
" got: (#{actual_input.inspect}, {:one=>1}) (options hash)\n" \
149153
"Diff:\n" \
150154
"@@ -1 +1 @@\n" \
151155
"-[#{expected_input.inspect}, {:one=>1}]\n" \
152156
"+[#{actual_input.inspect}, {:one=>1}]\n"
153-
)
157+
158+
message = message.gsub('=>',' => ') if RUBY_VERSION.to_f > 3.3
159+
160+
expect {
161+
options = { one: 1 }
162+
d.foo(actual_input, options)
163+
}.to fail_with(message)
154164
end
155165
end
156166
RUBY
@@ -172,28 +182,34 @@
172182
if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash?
173183
eval <<-'RUBY', nil, __FILE__, __LINE__ + 1
174184
it "prints a diff when keyword argument were expected but got an option hash (using splat)" do
175-
expect(d).to receive(:foo).with(:positional, **expected_hash)
176-
expect {
177-
d.foo(:positional, expected_hash)
178-
}.to fail_with(
185+
message =
179186
"#{d.inspect} received :foo with unexpected arguments\n" \
180187
" expected: (:positional, {:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \
181188
" got: (:positional, {:baz=>:quz, :foo=>:bar}) (options hash)"
182-
)
189+
190+
message.gsub!('=>',' => ') if RUBY_VERSION.to_f > 3.3
191+
192+
expect(d).to receive(:foo).with(:positional, **expected_hash)
193+
expect {
194+
d.foo(:positional, expected_hash)
195+
}.to fail_with(message)
183196
end
184197
RUBY
185198

186199
eval <<-'RUBY', nil, __FILE__, __LINE__ + 1
187200
it "prints a diff when keyword argument were expected but got an option hash (literal)" do
201+
message =
202+
"#{d.inspect} received :foo with unexpected arguments\n" \
203+
" expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \
204+
" got: (:positional, {:keyword=>1}) (options hash)"
205+
206+
message.gsub!('=>',' => ') if RUBY_VERSION.to_f > 3.3
207+
188208
expect(d).to receive(:foo).with(:positional, keyword: 1)
189209
expect {
190210
options = { keyword: 1 }
191211
d.foo(:positional, options)
192-
}.to fail_with(
193-
"#{d.inspect} received :foo with unexpected arguments\n" \
194-
" expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \
195-
" got: (:positional, {:keyword=>1}) (options hash)"
196-
)
212+
}.to fail_with(message)
197213
end
198214
RUBY
199215

@@ -206,18 +222,21 @@
206222
207223
expect(d).to receive(:foo).with(expected_input, one: 1)
208224
209-
expect {
210-
options = { one: 1 }
211-
d.foo(actual_input, options)
212-
}.to fail_with(
225+
message =
213226
"#{d.inspect} received :foo with unexpected arguments\n" \
214227
" expected: (#{expected_input.inspect}, {:one=>1}) (keyword arguments)\n" \
215228
" got: (#{actual_input.inspect}, {:one=>1}) (options hash)\n" \
216229
"Diff:\n" \
217230
"@@ -1 +1 @@\n" \
218231
"-[#{expected_input.inspect}, {:one=>1}]\n" \
219232
"+[#{actual_input.inspect}, {:one=>1}]\n"
220-
)
233+
234+
message = message.gsub('=>', ' => ') if RUBY_VERSION.to_f > 3.3
235+
236+
expect {
237+
options = { one: 1 }
238+
d.foo(actual_input, options)
239+
}.to fail_with(message)
221240
end
222241
RUBY
223242
end
@@ -232,6 +251,11 @@
232251
def hash_regex_inspect(hash)
233252
"\\{(#{hash.map { |key, value| "#{key.inspect}=>#{value.inspect}.*" }.join "|"}){#{hash.size}}\\}"
234253
end
254+
elsif RUBY_VERSION.to_f > 3.3
255+
# Ruby head / 3.4 is changing the hash syntax inspect, but we use PP when diffing which just spaces out hashrockets
256+
def hash_regex_inspect(hash)
257+
Regexp.escape("{#{hash.map { |key, value| "#{key.inspect} => #{value.inspect}"}.join(", ")}}")
258+
end
235259
else
236260
def hash_regex_inspect(hash)
237261
Regexp.escape(hash.inspect)

Diff for: spec/rspec/mocks/double_spec.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -526,10 +526,17 @@ def initialize(amount, units)
526526

527527
if kw_args_supported?
528528
it 'fails when calling yielding method with invalid kw args' do
529+
message =
530+
if RUBY_VERSION.to_f > 3.3
531+
'#<Double "test double"> yielded |{:x => 1, :y => 2}| to block with optional keyword args (:x)'
532+
else
533+
'#<Double "test double"> yielded |{:x=>1, :y=>2}| to block with optional keyword args (:x)'
534+
end
535+
529536
expect(@double).to receive(:yield_back).and_yield(:x => 1, :y => 2)
530537
expect {
531538
eval("@double.yield_back { |x: 1| }")
532-
}.to fail_with '#<Double "test double"> yielded |{:x=>1, :y=>2}| to block with optional keyword args (:x)'
539+
}.to fail_with message
533540
end
534541
end
535542

Diff for: spec/rspec/mocks/hash_excluding_matcher_spec.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ module ArgumentMatchers
44
RSpec.describe HashExcludingMatcher do
55

66
it "describes itself properly" do
7-
expect(HashExcludingMatcher.new(:a => 5).description).to eq "hash_not_including(:a=>5)"
7+
message =
8+
if RUBY_VERSION.to_f > 3.3
9+
"hash_not_including(a: 5)"
10+
else
11+
"hash_not_including(:a=>5)"
12+
end
13+
14+
expect(HashExcludingMatcher.new(:a => 5).description).to eq message
815
end
916

1017
describe "passing" do

Diff for: spec/rspec/mocks/hash_including_matcher_spec.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ module ArgumentMatchers
44
RSpec.describe HashIncludingMatcher do
55

66
it "describes itself properly" do
7-
expect(HashIncludingMatcher.new(:a => 1).description).to eq "hash_including(:a=>1)"
7+
message =
8+
if RUBY_VERSION.to_f > 3.3
9+
"hash_including(a: 1)"
10+
else
11+
"hash_including(:a=>1)"
12+
end
13+
14+
expect(HashIncludingMatcher.new(:a => 1).description).to eq message
815
end
916

1017
it "describes passed matchers" do

Diff for: spec/rspec/mocks/matchers/receive_spec.rb

+19-7
Original file line numberDiff line numberDiff line change
@@ -130,17 +130,24 @@ def kw_args_method(a:, b:); end
130130
dbl.kw_args_method(a: 1, b: 2)
131131
end
132132
133-
if RUBY_VERSION >= '3.0'
133+
if RUBY_VERSION.to_f >= 3.0
134134
it "fails to expect to receive hash with keyword args" do
135135
expect {
136136
dbl = instance_double(TestObject)
137137
expect(dbl).to receive(:kw_args_method).with(a: 1, b: 2)
138138
dbl.kw_args_method({a: 1, b: 2})
139139
}.to fail_with do |failure|
140140
reset_all
141-
expect(failure.message)
142-
.to include('expected: ({:a=>1, :b=>2}) (keyword arguments)')
143-
.and include('got: ({:a=>1, :b=>2}) (options hash)')
141+
142+
if RUBY_VERSION.to_f > 3.3
143+
expect(failure.message)
144+
.to include('expected: ({:a => 1, :b => 2}) (keyword arguments)')
145+
.and include('got: ({:a => 1, :b => 2}) (options hash)')
146+
else
147+
expect(failure.message)
148+
.to include('expected: ({:a=>1, :b=>2}) (keyword arguments)')
149+
.and include('got: ({:a=>1, :b=>2}) (options hash)')
150+
end
144151
end
145152
end
146153
else
@@ -505,9 +512,14 @@ def receiver.method_missing(*); end # a poor man's stub...
505512
receiver.foo(1, :bar => 2)
506513
receiver.foo(1, :bar => 3)
507514

508-
expect { verify_all }.to(
509-
raise_error(/received: 2 times with arguments: \(anything, hash_including\(:bar=>"anything"\)\)$/)
510-
)
515+
message =
516+
if RUBY_VERSION.to_f > 3.3
517+
/received: 2 times with arguments: \(anything, hash_including\(bar: "anything"\)\)$/
518+
else
519+
/received: 2 times with arguments: \(anything, hash_including\(:bar=>"anything"\)\)$/
520+
end
521+
522+
expect { verify_all }.to raise_error(message)
511523
end
512524
end
513525
end

Diff for: spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb

+9-2
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,19 @@ module Mocks
130130
dbl.kw_args_method(1, :required_arg => 2, :optional_arg => 3)
131131
end
132132

133-
if RUBY_VERSION >= "3"
133+
if RUBY_VERSION.to_f >= 3.0
134134
it "fails to match against a hash submitted as a positional argument and received as keyword arguments in Ruby 3.0 or later", :reset => true do
135+
messages =
136+
if RUBY_VERSION.to_f > 3.3
137+
["expected: (1, {:optional_arg => 3, :required_arg => 2}) (keyword arguments)", "got: (1, {:optional_arg => 3, :required_arg => 2}) (options hash)"]
138+
else
139+
["expected: (1, {:optional_arg=>3, :required_arg=>2}) (keyword arguments)", "got: (1, {:optional_arg=>3, :required_arg=>2}) (options hash)"]
140+
end
141+
135142
expect(dbl).to receive(:kw_args_method).with(1, :required_arg => 2, :optional_arg => 3)
136143
expect do
137144
dbl.kw_args_method(1, {:required_arg => 2, :optional_arg => 3})
138-
end.to fail_with(a_string_including("expected: (1, {:optional_arg=>3, :required_arg=>2}) (keyword arguments)", "got: (1, {:optional_arg=>3, :required_arg=>2}) (options hash)"))
145+
end.to fail_with(a_string_including(*messages))
139146
end
140147
else
141148
it "matches against a hash submitted as a positional argument and received as keyword arguments in Ruby 2.7 or before" do

0 commit comments

Comments
 (0)