diff --git a/rspec-mocks-pr1597-ruby34-formatting.patch b/rspec-mocks-pr1597-ruby34-formatting.patch new file mode 100644 index 0000000..e99a6eb --- /dev/null +++ b/rspec-mocks-pr1597-ruby34-formatting.patch @@ -0,0 +1,429 @@ +From f8b49348d02d0220e20391665f7418f9212dac02 Mon Sep 17 00:00:00 2001 +From: Jon Rowe +Date: Fri, 18 Oct 2024 21:39:26 +0100 +Subject: [PATCH] Relax specs for Ruby 3.4 hash formatting + +--- + .../matching_arguments.feature | 6 +- + .../step_definitions/additional_cli_steps.rb | 7 +- + spec/rspec/mocks/argument_matchers_spec.rb | 14 ++-- + spec/rspec/mocks/diffing_spec.rb | 84 ++++++++++++------- + spec/rspec/mocks/double_spec.rb | 9 +- + .../mocks/hash_excluding_matcher_spec.rb | 9 +- + .../mocks/hash_including_matcher_spec.rb | 9 +- + spec/rspec/mocks/matchers/receive_spec.rb | 26 ++++-- + .../expected_arg_verification_spec.rb | 11 ++- + 9 files changed, 124 insertions(+), 51 deletions(-) + +diff --git a/features/setting_constraints/matching_arguments.feature b/features/setting_constraints/matching_arguments.feature +index caea74248..cad5cea4c 100644 +--- a/features/setting_constraints/matching_arguments.feature ++++ b/features/setting_constraints/matching_arguments.feature +@@ -73,7 +73,7 @@ Feature: Matching arguments + end + """ + When I run `rspec keyword_example_spec.rb` +- Then it should fail with the following output: ++ Then it should fail with the following output, ignoring hash syntax: + | 2 examples, 1 failure | + | | + | Failure/Error: dbl.foo(bar: "incorrect") | +@@ -100,7 +100,7 @@ Feature: Matching arguments + end + """ + When I run `rspec keyword_example_spec.rb` +- Then it should fail with the following output: ++ Then it should fail with the following output, ignoring hash syntax: + | 1 example, 1 failure | + | | + | Failure/Error: dbl.foo({bar: "also incorrect"}) | +@@ -156,7 +156,7 @@ Feature: Matching arguments + end + """ + When I run `rspec rspec_satisfy_spec.rb` +- Then it should fail with the following output: ++ Then it should fail with the following output, ignoring hash syntax: + | 2 examples, 1 failure | + | | + | Failure/Error: dbl.foo({ :a => { :b => { :c => 3 } } }) | +diff --git a/features/step_definitions/additional_cli_steps.rb b/features/step_definitions/additional_cli_steps.rb +index 77f8c0f30..acf1117e0 100644 +--- a/features/step_definitions/additional_cli_steps.rb ++++ b/features/step_definitions/additional_cli_steps.rb +@@ -22,8 +22,13 @@ + diffable + end + +-Then /^it should fail with the following output:$/ do |table| ++Then /^it should fail with the following output(, ignoring hash syntax)?:$/ do |ignore_hash_syntax, table| + step %q(the exit status should be 1) + lines = table.raw.flatten.reject(&:empty?) ++ ++ if ignore_hash_syntax && RUBY_VERSION.to_f > 3.3 ++ lines = lines.map { |line| line.gsub(/([^\s])=>/, '\1 => ') } ++ end ++ + expect(all_output).to match_table(lines) + end +diff --git a/spec/rspec/mocks/argument_matchers_spec.rb b/spec/rspec/mocks/argument_matchers_spec.rb +index eb101a04c..8f31d1786 100644 +--- a/spec/rspec/mocks/argument_matchers_spec.rb ++++ b/spec/rspec/mocks/argument_matchers_spec.rb +@@ -256,7 +256,7 @@ module Mocks + expect(a_double).to receive(:random_call).with(hash_including(:a => 1)) + expect { + a_double.random_call(:a => 2) +- }.to fail_including "expected: (hash_including(:a=>1))" ++ }.to fail_including "expected: (hash_including(#{hash_syntax(:a => 1)}))" + end + end + +@@ -270,7 +270,7 @@ module Mocks + expect(a_double).to receive(:random_call).with(hash_excluding(:a => 1)) + expect { + a_double.random_call(:a => 1) +- }.to fail_including "expected: (hash_not_including(:a=>1))" ++ }.to fail_including "expected: (hash_not_including(#{hash_syntax(:a => 1)}))" + end + end + +@@ -431,7 +431,7 @@ def ==(other) + expect(a_double).to receive(:random_call).with(:a => "a", :b => "b") + expect do + a_double.random_call(opts) +- end.to fail_with(/expected: \(\{(:a=>\"a\", :b=>\"b\"|:b=>\"b\", :a=>\"a\")\}\)/) ++ end.to fail_with(/expected: \(\{(:a\s*=>\s*\"a\", :b\s*=>\s*\"b\"|:b\s*=>\s*\"b\", :a\s*=>\s*\"a\")\}\)/) + end + else + 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) + expect(a_double).to receive(:random_call).with(:a => "b", :c => "d") + expect do + a_double.random_call(:a => "b", :c => "e") +- end.to fail_with(/expected: \(\{(:a=>\"b\", :c=>\"d\"|:c=>\"d\", :a=>\"b\")\}\)/) ++ end.to fail_with(/expected: \(\{(:a\s*=>\s*\"b\", :c\s*=>\s*\"d\"|:c\s*=>\s*\"d\", :a\s*=>\s*\"b\")\}\)/) + end + + it "fails for a hash w/ wrong keys", :reset => true do + expect(a_double).to receive(:random_call).with(:a => "b", :c => "d") + expect do + a_double.random_call("a" => "b", "c" => "d") +- end.to fail_with(/expected: \(\{(:a=>\"b\", :c=>\"d\"|:c=>\"d\", :a=>\"b\")\}\)/) ++ end.to fail_with(/expected: \(\{(:a\s*=>\s*\"b\", :c\s*=>\s*\"d\"|:c\s*=>\s*\"d\", :a\s*=>\s*\"b\")\}\)/) + end + + it "matches a class against itself" do +@@ -502,6 +502,10 @@ def ==(other) + expect { a_double.msg 3 }.to fail_including "expected: (my_thing)" + end + end ++ ++ def hash_syntax(hash) ++ hash.inspect.gsub(/\{(.*)\}/, '\1') ++ end + end + end + end +diff --git a/spec/rspec/mocks/diffing_spec.rb b/spec/rspec/mocks/diffing_spec.rb +index e40fa55b6..8be6510da 100644 +--- a/spec/rspec/mocks/diffing_spec.rb ++++ b/spec/rspec/mocks/diffing_spec.rb +@@ -100,15 +100,18 @@ + if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash? + eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 + it "prints a diff when keyword argument were expected but got an option hash (using splat)" do ++ message = ++ "# received :foo with unexpected arguments\n" \ ++ " expected: ({:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \ ++ " got: ({:baz=>:quz, :foo=>:bar}) (options hash)" ++ ++ message = message.gsub('=>', ' => ') if RUBY_VERSION.to_f > 3.3 ++ + with_unfulfilled_double do |d| + expect(d).to receive(:foo).with(**expected_hash) + expect { + d.foo(expected_hash) +- }.to fail_with( +- "# received :foo with unexpected arguments\n" \ +- " expected: ({:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \ +- " got: ({:baz=>:quz, :foo=>:bar}) (options hash)" +- ) ++ }.to fail_with(message) + end + end + RUBY +@@ -117,14 +120,18 @@ + it "prints a diff when keyword argument were expected but got an option hash (literal)" do + with_unfulfilled_double do |d| + expect(d).to receive(:foo).with(:positional, keyword: 1) +- expect { +- options = { keyword: 1 } +- d.foo(:positional, options) +- }.to fail_with( ++ ++ message = + "# received :foo with unexpected arguments\n" \ + " expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \ + " got: (:positional, {:keyword=>1}) (options hash)" +- ) ++ ++ message = message.gsub('=>',' => ') if RUBY_VERSION.to_f > 3.3 ++ ++ expect { ++ options = { keyword: 1 } ++ d.foo(:positional, options) ++ }.to fail_with(message) + end + end + RUBY +@@ -139,10 +146,7 @@ + + expect(d).to receive(:foo).with(expected_input, one: 1) + +- expect { +- options = { one: 1 } +- d.foo(actual_input, options) +- }.to fail_with( ++ message = + "# received :foo with unexpected arguments\n" \ + " expected: (#{expected_input.inspect}, {:one=>1}) (keyword arguments)\n" \ + " got: (#{actual_input.inspect}, {:one=>1}) (options hash)\n" \ +@@ -150,7 +154,13 @@ + "@@ -1 +1 @@\n" \ + "-[#{expected_input.inspect}, {:one=>1}]\n" \ + "+[#{actual_input.inspect}, {:one=>1}]\n" +- ) ++ ++ message = message.gsub('=>',' => ') if RUBY_VERSION.to_f > 3.3 ++ ++ expect { ++ options = { one: 1 } ++ d.foo(actual_input, options) ++ }.to fail_with(message) + end + end + RUBY +@@ -172,28 +182,34 @@ + if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash? + eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 + it "prints a diff when keyword argument were expected but got an option hash (using splat)" do +- expect(d).to receive(:foo).with(:positional, **expected_hash) +- expect { +- d.foo(:positional, expected_hash) +- }.to fail_with( ++ message = + "#{d.inspect} received :foo with unexpected arguments\n" \ + " expected: (:positional, {:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \ + " got: (:positional, {:baz=>:quz, :foo=>:bar}) (options hash)" +- ) ++ ++ message.gsub!('=>',' => ') if RUBY_VERSION.to_f > 3.3 ++ ++ expect(d).to receive(:foo).with(:positional, **expected_hash) ++ expect { ++ d.foo(:positional, expected_hash) ++ }.to fail_with(message) + end + RUBY + + eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 + it "prints a diff when keyword argument were expected but got an option hash (literal)" do ++ message = ++ "#{d.inspect} received :foo with unexpected arguments\n" \ ++ " expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \ ++ " got: (:positional, {:keyword=>1}) (options hash)" ++ ++ message.gsub!('=>',' => ') if RUBY_VERSION.to_f > 3.3 ++ + expect(d).to receive(:foo).with(:positional, keyword: 1) + expect { + options = { keyword: 1 } + d.foo(:positional, options) +- }.to fail_with( +- "#{d.inspect} received :foo with unexpected arguments\n" \ +- " expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \ +- " got: (:positional, {:keyword=>1}) (options hash)" +- ) ++ }.to fail_with(message) + end + RUBY + +@@ -206,10 +222,7 @@ + + expect(d).to receive(:foo).with(expected_input, one: 1) + +- expect { +- options = { one: 1 } +- d.foo(actual_input, options) +- }.to fail_with( ++ message = + "#{d.inspect} received :foo with unexpected arguments\n" \ + " expected: (#{expected_input.inspect}, {:one=>1}) (keyword arguments)\n" \ + " got: (#{actual_input.inspect}, {:one=>1}) (options hash)\n" \ +@@ -217,7 +230,13 @@ + "@@ -1 +1 @@\n" \ + "-[#{expected_input.inspect}, {:one=>1}]\n" \ + "+[#{actual_input.inspect}, {:one=>1}]\n" +- ) ++ ++ message = message.gsub('=>', ' => ') if RUBY_VERSION.to_f > 3.3 ++ ++ expect { ++ options = { one: 1 } ++ d.foo(actual_input, options) ++ }.to fail_with(message) + end + RUBY + end +@@ -232,6 +251,11 @@ + def hash_regex_inspect(hash) + "\\{(#{hash.map { |key, value| "#{key.inspect}=>#{value.inspect}.*" }.join "|"}){#{hash.size}}\\}" + end ++ elsif RUBY_VERSION.to_f > 3.3 ++ # Ruby head / 3.4 is changing the hash syntax inspect, but we use PP when diffing which just spaces out hashrockets ++ def hash_regex_inspect(hash) ++ Regexp.escape("{#{hash.map { |key, value| "#{key.inspect} => #{value.inspect}"}.join(", ")}}") ++ end + else + def hash_regex_inspect(hash) + Regexp.escape(hash.inspect) +diff --git a/spec/rspec/mocks/double_spec.rb b/spec/rspec/mocks/double_spec.rb +index d5dff63b3..ac65c590f 100644 +--- a/spec/rspec/mocks/double_spec.rb ++++ b/spec/rspec/mocks/double_spec.rb +@@ -526,10 +526,17 @@ def initialize(amount, units) + + if kw_args_supported? + it 'fails when calling yielding method with invalid kw args' do ++ message = ++ if RUBY_VERSION.to_f > 3.3 ++ '# yielded |{:x => 1, :y => 2}| to block with optional keyword args (:x)' ++ else ++ '# yielded |{:x=>1, :y=>2}| to block with optional keyword args (:x)' ++ end ++ + expect(@double).to receive(:yield_back).and_yield(:x => 1, :y => 2) + expect { + eval("@double.yield_back { |x: 1| }") +- }.to fail_with '# yielded |{:x=>1, :y=>2}| to block with optional keyword args (:x)' ++ }.to fail_with message + end + end + +diff --git a/spec/rspec/mocks/hash_excluding_matcher_spec.rb b/spec/rspec/mocks/hash_excluding_matcher_spec.rb +index fc0faed05..3fca99823 100644 +--- a/spec/rspec/mocks/hash_excluding_matcher_spec.rb ++++ b/spec/rspec/mocks/hash_excluding_matcher_spec.rb +@@ -4,7 +4,14 @@ module ArgumentMatchers + RSpec.describe HashExcludingMatcher do + + it "describes itself properly" do +- expect(HashExcludingMatcher.new(:a => 5).description).to eq "hash_not_including(:a=>5)" ++ message = ++ if RUBY_VERSION.to_f > 3.3 ++ "hash_not_including(a: 5)" ++ else ++ "hash_not_including(:a=>5)" ++ end ++ ++ expect(HashExcludingMatcher.new(:a => 5).description).to eq message + end + + describe "passing" do +diff --git a/spec/rspec/mocks/hash_including_matcher_spec.rb b/spec/rspec/mocks/hash_including_matcher_spec.rb +index ad5e8587a..057aec55d 100644 +--- a/spec/rspec/mocks/hash_including_matcher_spec.rb ++++ b/spec/rspec/mocks/hash_including_matcher_spec.rb +@@ -4,7 +4,14 @@ module ArgumentMatchers + RSpec.describe HashIncludingMatcher do + + it "describes itself properly" do +- expect(HashIncludingMatcher.new(:a => 1).description).to eq "hash_including(:a=>1)" ++ message = ++ if RUBY_VERSION.to_f > 3.3 ++ "hash_including(a: 1)" ++ else ++ "hash_including(:a=>1)" ++ end ++ ++ expect(HashIncludingMatcher.new(:a => 1).description).to eq message + end + + it "describes passed matchers" do +diff --git a/spec/rspec/mocks/matchers/receive_spec.rb b/spec/rspec/mocks/matchers/receive_spec.rb +index 1b71dd58f..abf266935 100644 +--- a/spec/rspec/mocks/matchers/receive_spec.rb ++++ b/spec/rspec/mocks/matchers/receive_spec.rb +@@ -130,7 +130,7 @@ def kw_args_method(a:, b:); end + dbl.kw_args_method(a: 1, b: 2) + end + +- if RUBY_VERSION >= '3.0' ++ if RUBY_VERSION.to_f >= 3.0 + it "fails to expect to receive hash with keyword args" do + expect { + dbl = instance_double(TestObject) +@@ -138,9 +138,16 @@ def kw_args_method(a:, b:); end + dbl.kw_args_method({a: 1, b: 2}) + }.to fail_with do |failure| + reset_all +- expect(failure.message) +- .to include('expected: ({:a=>1, :b=>2}) (keyword arguments)') +- .and include('got: ({:a=>1, :b=>2}) (options hash)') ++ ++ if RUBY_VERSION.to_f > 3.3 ++ expect(failure.message) ++ .to include('expected: ({:a => 1, :b => 2}) (keyword arguments)') ++ .and include('got: ({:a => 1, :b => 2}) (options hash)') ++ else ++ expect(failure.message) ++ .to include('expected: ({:a=>1, :b=>2}) (keyword arguments)') ++ .and include('got: ({:a=>1, :b=>2}) (options hash)') ++ end + end + end + else +@@ -505,9 +512,14 @@ def receiver.method_missing(*); end # a poor man's stub... + receiver.foo(1, :bar => 2) + receiver.foo(1, :bar => 3) + +- expect { verify_all }.to( +- raise_error(/received: 2 times with arguments: \(anything, hash_including\(:bar=>"anything"\)\)$/) +- ) ++ message = ++ if RUBY_VERSION.to_f > 3.3 ++ /received: 2 times with arguments: \(anything, hash_including\(bar: "anything"\)\)$/ ++ else ++ /received: 2 times with arguments: \(anything, hash_including\(:bar=>"anything"\)\)$/ ++ end ++ ++ expect { verify_all }.to raise_error(message) + end + end + end +diff --git a/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb b/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb +index d39995341..1860afa1a 100644 +--- a/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb ++++ b/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb +@@ -130,12 +130,19 @@ module Mocks + dbl.kw_args_method(1, :required_arg => 2, :optional_arg => 3) + end + +- if RUBY_VERSION >= "3" ++ if RUBY_VERSION.to_f >= 3.0 + 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 ++ messages = ++ if RUBY_VERSION.to_f > 3.3 ++ ["expected: (1, {:optional_arg => 3, :required_arg => 2}) (keyword arguments)", "got: (1, {:optional_arg => 3, :required_arg => 2}) (options hash)"] ++ else ++ ["expected: (1, {:optional_arg=>3, :required_arg=>2}) (keyword arguments)", "got: (1, {:optional_arg=>3, :required_arg=>2}) (options hash)"] ++ end ++ + expect(dbl).to receive(:kw_args_method).with(1, :required_arg => 2, :optional_arg => 3) + expect do + dbl.kw_args_method(1, {:required_arg => 2, :optional_arg => 3}) +- 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)")) ++ end.to fail_with(a_string_including(*messages)) + end + else + it "matches against a hash submitted as a positional argument and received as keyword arguments in Ruby 2.7 or before" do diff --git a/rspec-mocks-pr164-ruby34-hash-syntax.patch b/rspec-mocks-pr164-ruby34-hash-syntax.patch new file mode 100644 index 0000000..2f5bec0 --- /dev/null +++ b/rspec-mocks-pr164-ruby34-hash-syntax.patch @@ -0,0 +1,190 @@ +From 9310b4b72e205c6352c4b30015a3b8f3d2fb02e8 Mon Sep 17 00:00:00 2001 +From: Jon Rowe +Date: Thu, 26 Dec 2024 11:06:37 +0000 +Subject: [PATCH 1/2] Format hashes in new {a: :b} format on Ruby 3.4 + +--- + .../step_definitions/additional_cli_steps.rb | 2 +- + .../rspec/mocks/argument_matchers_spec.rb | 24 ++++++++++++++++--- + rspec-mocks/spec/rspec/mocks/diffing_spec.rb | 17 +++++-------- + rspec-mocks/spec/rspec/mocks/double_spec.rb | 2 +- + .../spec/rspec/mocks/matchers/receive_spec.rb | 4 ++-- + .../expected_arg_verification_spec.rb | 2 +- + .../lib/rspec/support/object_formatter.rb | 2 ++ + .../spec/rspec/support/differ_spec.rb | 2 +- + .../rspec/support/object_formatter_spec.rb | 22 +++++++++++++++-- + 9 files changed, 55 insertions(+), 22 deletions(-) + +diff --git a/rspec-mocks/features/step_definitions/additional_cli_steps.rb b/rspec-mocks/features/step_definitions/additional_cli_steps.rb +index acf1117e0..9ccfac5b1 100644 +--- a/rspec-mocks/features/step_definitions/additional_cli_steps.rb ++++ b/rspec-mocks/features/step_definitions/additional_cli_steps.rb +@@ -27,7 +27,7 @@ + lines = table.raw.flatten.reject(&:empty?) + + if ignore_hash_syntax && RUBY_VERSION.to_f > 3.3 +- lines = lines.map { |line| line.gsub(/([^\s])=>/, '\1 => ') } ++ lines = lines.map { |line| line.gsub(/:(\w+)=>/, '\1: ') } + end + + expect(all_output).to match_table(lines) +diff --git a/rspec-mocks/spec/rspec/mocks/argument_matchers_spec.rb b/rspec-mocks/spec/rspec/mocks/argument_matchers_spec.rb +index 8f31d1786..4bffa727d 100644 +--- a/rspec-mocks/spec/rspec/mocks/argument_matchers_spec.rb ++++ b/rspec-mocks/spec/rspec/mocks/argument_matchers_spec.rb +@@ -431,7 +431,13 @@ def ==(other) + expect(a_double).to receive(:random_call).with(:a => "a", :b => "b") + expect do + a_double.random_call(opts) +- end.to fail_with(/expected: \(\{(:a\s*=>\s*\"a\", :b\s*=>\s*\"b\"|:b\s*=>\s*\"b\", :a\s*=>\s*\"a\")\}\)/) ++ end.to fail_with( ++ if RUBY_VERSION.to_f > 3.3 ++ /expected: \(\{a: \"a\", b: \"b\"\}\)/ ++ else ++ /expected: \(\{(:a\s*=>\s*\"a\", :b\s*=>\s*\"b\"|:b\s*=>\s*\"b\", :a\s*=>\s*\"a\")\}\)/ ++ end ++ ) + end + else + it "matches against a hash submitted as a positional argument and received as keyword arguments in Ruby 2.7 or before" do +@@ -445,14 +451,26 @@ def ==(other) + expect(a_double).to receive(:random_call).with(:a => "b", :c => "d") + expect do + a_double.random_call(:a => "b", :c => "e") +- end.to fail_with(/expected: \(\{(:a\s*=>\s*\"b\", :c\s*=>\s*\"d\"|:c\s*=>\s*\"d\", :a\s*=>\s*\"b\")\}\)/) ++ end.to fail_with( ++ if RUBY_VERSION.to_f > 3.3 ++ /expected: \(\{a: \"b\", c: \"d\"\}\)/ ++ else ++ /expected: \(\{(:a\s*=>\s*\"b\", :c\s*=>\s*\"d\"|:c\s*=>\s*\"d\", :a\s*=>\s*\"b\")\}\)/ ++ end ++ ) + end + + it "fails for a hash w/ wrong keys", :reset => true do + expect(a_double).to receive(:random_call).with(:a => "b", :c => "d") + expect do + a_double.random_call("a" => "b", "c" => "d") +- end.to fail_with(/expected: \(\{(:a\s*=>\s*\"b\", :c\s*=>\s*\"d\"|:c\s*=>\s*\"d\", :a\s*=>\s*\"b\")\}\)/) ++ end.to fail_with( ++ if RUBY_VERSION.to_f > 3.3 ++ /expected: \(\{a: \"b\", c: \"d\"\}\)/ ++ else ++ /expected: \(\{(:a\s*=>\s*\"b\", :c\s*=>\s*\"d\"|:c\s*=>\s*\"d\", :a\s*=>\s*\"b\")\}\)/ ++ end ++ ) + end + + it "matches a class against itself" do +diff --git a/rspec-mocks/spec/rspec/mocks/diffing_spec.rb b/rspec-mocks/spec/rspec/mocks/diffing_spec.rb +index f071cc1ec..b4492b4e8 100644 +--- a/rspec-mocks/spec/rspec/mocks/diffing_spec.rb ++++ b/rspec-mocks/spec/rspec/mocks/diffing_spec.rb +@@ -105,7 +105,7 @@ + " expected: ({:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \ + " got: ({:baz=>:quz, :foo=>:bar}) (options hash)" + +- message = message.gsub('=>', ' => ') if RUBY_VERSION.to_f > 3.3 ++ message = message.gsub(/:(\w+)=>/, '\1: ') if RUBY_VERSION.to_f > 3.3 + + with_unfulfilled_double do |d| + expect(d).to receive(:foo).with(**expected_hash) +@@ -126,7 +126,7 @@ + " expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \ + " got: (:positional, {:keyword=>1}) (options hash)" + +- message = message.gsub('=>',' => ') if RUBY_VERSION.to_f > 3.3 ++ message = message.gsub(/:(\w+)=>/, '\1: ') if RUBY_VERSION.to_f > 3.3 + + expect { + options = { keyword: 1 } +@@ -155,7 +155,7 @@ + "-[#{expected_input.inspect}, {:one=>1}]\n" \ + "+[#{actual_input.inspect}, {:one=>1}]\n" + +- message = message.gsub('=>',' => ') if RUBY_VERSION.to_f > 3.3 ++ message = message.gsub(/:(\w+)=>/, '\1: ') if RUBY_VERSION.to_f > 3.3 + + expect { + options = { one: 1 } +@@ -187,7 +187,7 @@ + " expected: (:positional, {:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \ + " got: (:positional, {:baz=>:quz, :foo=>:bar}) (options hash)" + +- message.gsub!('=>',' => ') if RUBY_VERSION.to_f > 3.3 ++ message = message.gsub(/:(\w+)=>/, '\1: ') if RUBY_VERSION.to_f > 3.3 + + expect(d).to receive(:foo).with(:positional, **expected_hash) + expect { +@@ -203,7 +203,7 @@ + " expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \ + " got: (:positional, {:keyword=>1}) (options hash)" + +- message.gsub!('=>',' => ') if RUBY_VERSION.to_f > 3.3 ++ message = message.gsub(/:(\w+)=>/, '\1: ') if RUBY_VERSION.to_f > 3.3 + + expect(d).to receive(:foo).with(:positional, keyword: 1) + expect { +@@ -231,7 +231,7 @@ + "-[#{expected_input.inspect}, {:one=>1}]\n" \ + "+[#{actual_input.inspect}, {:one=>1}]\n" + +- message = message.gsub('=>', ' => ') if RUBY_VERSION.to_f > 3.3 ++ message = message.gsub(/:(\w+)=>/, '\1: ') if RUBY_VERSION.to_f > 3.3 + + expect { + options = { one: 1 } +@@ -251,11 +251,6 @@ + def hash_regex_inspect(hash) + "\\{(#{hash.map { |key, value| "#{key.inspect}=>#{value.inspect}.*" }.join "|"}){#{hash.size}}\\}" + end +- elsif RUBY_VERSION.to_f > 3.3 +- # Ruby head / 3.4 is changing the hash syntax inspect, but we use PP when diffing which just spaces out hashrockets +- def hash_regex_inspect(hash) +- Regexp.escape("{#{hash.map { |key, value| "#{key.inspect} => #{value.inspect}"}.join(", ")}}") +- end + else + def hash_regex_inspect(hash) + Regexp.escape(hash.inspect) +diff --git a/rspec-mocks/spec/rspec/mocks/double_spec.rb b/rspec-mocks/spec/rspec/mocks/double_spec.rb +index ac65c590f..9738edfa7 100644 +--- a/rspec-mocks/spec/rspec/mocks/double_spec.rb ++++ b/rspec-mocks/spec/rspec/mocks/double_spec.rb +@@ -528,7 +528,7 @@ def initialize(amount, units) + it 'fails when calling yielding method with invalid kw args' do + message = + if RUBY_VERSION.to_f > 3.3 +- '# yielded |{:x => 1, :y => 2}| to block with optional keyword args (:x)' ++ '# yielded |{x: 1, y: 2}| to block with optional keyword args (:x)' + else + '# yielded |{:x=>1, :y=>2}| to block with optional keyword args (:x)' + end +diff --git a/rspec-mocks/spec/rspec/mocks/matchers/receive_spec.rb b/rspec-mocks/spec/rspec/mocks/matchers/receive_spec.rb +index 3e71bd289..307c86a6f 100644 +--- a/rspec-mocks/spec/rspec/mocks/matchers/receive_spec.rb ++++ b/rspec-mocks/spec/rspec/mocks/matchers/receive_spec.rb +@@ -141,8 +141,8 @@ def kw_args_method(a:, b:); end + + if RUBY_VERSION.to_f > 3.3 + expect(failure.message) +- .to include('expected: ({:a => 1, :b => 2}) (keyword arguments)') +- .and include('got: ({:a => 1, :b => 2}) (options hash)') ++ .to include('expected: ({a: 1, b: 2}) (keyword arguments)') ++ .and include('got: ({a: 1, b: 2}) (options hash)') + else + expect(failure.message) + .to include('expected: ({:a=>1, :b=>2}) (keyword arguments)') +diff --git a/rspec-mocks/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb b/rspec-mocks/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb +index a3f3d2034..48646a1e6 100644 +--- a/rspec-mocks/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb ++++ b/rspec-mocks/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb +@@ -134,7 +134,7 @@ module Mocks + 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 + messages = + if RUBY_VERSION.to_f > 3.3 +- ["expected: (1, {:optional_arg => 3, :required_arg => 2}) (keyword arguments)", "got: (1, {:optional_arg => 3, :required_arg => 2}) (options hash)"] ++ ["expected: (1, {optional_arg: 3, required_arg: 2}) (keyword arguments)", "got: (1, {optional_arg: 3, required_arg: 2}) (options hash)"] + else + ["expected: (1, {:optional_arg=>3, :required_arg=>2}) (keyword arguments)", "got: (1, {:optional_arg=>3, :required_arg=>2}) (options hash)"] + end + diff --git a/rspec-mocks-pr282-skip-mock-for-ruby4_0-inspect.patch b/rspec-mocks-pr282-skip-mock-for-ruby4_0-inspect.patch new file mode 100644 index 0000000..d1c309b --- /dev/null +++ b/rspec-mocks-pr282-skip-mock-for-ruby4_0-inspect.patch @@ -0,0 +1,35 @@ +From 939c4799993b7ff7e524fac701ae6490772ca6de Mon Sep 17 00:00:00 2001 +From: Jon Rowe +Date: Mon, 1 Dec 2025 14:08:25 +0000 +Subject: [PATCH] Skip mock for calls to `:respond_to?` from `Kernel#inspect` + +--- + rspec-mocks/lib/rspec/mocks/method_double.rb | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/rspec-mocks/lib/rspec/mocks/method_double.rb b/rspec-mocks/lib/rspec/mocks/method_double.rb +index e2edb1e21..3276c49a5 100644 +--- a/rspec-mocks/lib/rspec/mocks/method_double.rb ++++ b/rspec-mocks/lib/rspec/mocks/method_double.rb +@@ -68,8 +68,19 @@ def define_proxy_method + + save_original_implementation_callable! + definition_target.class_exec(self, method_name, @original_visibility || visibility) do |method_double, method_name, visibility| +- define_method(method_name) do |*args, &block| +- method_double.proxy_method_invoked(self, *args, &block) ++ if RUBY_VERSION.to_f > 3 && method_name == :respond_to? ++ define_method(method_name) do |*args, &block| ++ # This is a work around for a respond_to? check within kernel_inspect ++ if caller_locations[0].label == "Kernel#inspect" ++ super(*args, &block) ++ else ++ method_double.proxy_method_invoked(self, *args, &block) ++ end ++ end ++ else ++ define_method(method_name) do |*args, &block| ++ method_double.proxy_method_invoked(self, *args, &block) ++ end + end + # This can't be `if respond_to?(:ruby2_keywords, true)`, + # see https://github.com/rspec/rspec-mocks/pull/1385#issuecomment-755340298 diff --git a/rspec-related-create-full-tarball.sh b/rspec-related-create-full-tarball.sh index a847c6c..c0ba6bf 100644 --- a/rspec-related-create-full-tarball.sh +++ b/rspec-related-create-full-tarball.sh @@ -14,10 +14,9 @@ CURRDIR=$(pwd) TMPDIRPATH=$(mktemp -d /var/tmp/rspec-tar-XXXXXX) pushd $TMPDIRPATH -git clone https://github.com/rspec/$1.git -pushd $1 -git reset --hard v$2 -popd +git clone https://github.com/rspec/rspec.git +pushd rspec +git reset --hard $1-v$2 ln -sf $1 $1-$2 tar czf ${CURRDIR}/rubygem-$1-$2-full.tar.gz $1-$2/./ diff --git a/rubygem-rspec-mocks-3.12.0-display_keyword_hashes-additional.patch b/rubygem-rspec-mocks-3.12.0-display_keyword_hashes-additional.patch deleted file mode 100644 index 500ad7e..0000000 --- a/rubygem-rspec-mocks-3.12.0-display_keyword_hashes-additional.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -urp -x .git rspec-mocks-3.11.2/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb rspec-mocks-3.12.0/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb ---- rspec-mocks-3.11.2/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb 2022-10-26 16:39:18.000000000 +0900 -+++ rspec-mocks-3.12.0/spec/rspec/mocks/verifying_doubles/expected_arg_verification_spec.rb 2022-10-27 14:34:37.000000000 +0900 -@@ -135,7 +135,7 @@ module RSpec - expect(dbl).to receive(:kw_args_method).with(1, :required_arg => 2, :optional_arg => 3) - expect do - dbl.kw_args_method(1, {:required_arg => 2, :optional_arg => 3}) -- end.to fail_with(a_string_including("expected: (1, {:optional_arg=>3, :required_arg=>2})", "got: (1, {:optional_arg=>3, :required_arg=>2})")) -+ 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)")) - end - else - it "matches against a hash submitted as a positional argument and received as keyword arguments in Ruby 2.7 or before" do diff --git a/rubygem-rspec-mocks-3.12.0-display_keyword_hashes.patch b/rubygem-rspec-mocks-3.12.0-display_keyword_hashes.patch deleted file mode 100644 index cc6ea7c..0000000 --- a/rubygem-rspec-mocks-3.12.0-display_keyword_hashes.patch +++ /dev/null @@ -1,109 +0,0 @@ -From e931e818b577172b89fb4583fc336fbcd25df36b Mon Sep 17 00:00:00 2001 -From: Jean Boussier -Date: Fri, 18 Feb 2022 11:19:47 +0100 -Subject: [PATCH] Display keyword hashes in in expectation error messages - -Ref: https://github.com/vcr/vcr/pull/925 -Ref: https://github.com/rspec/rspec-mocks/pull/1394 - -I spent quite a lot of time figuring this error: - -``` - 2) VCR.turned_on passes options through to .turn_off! - Failure/Error: turn_off!(options) - - VCR received :turn_off! with unexpected arguments - expected: ({:ignore_cassettes=>true}) - got: ({:ignore_cassettes=>true}) - # ./lib/vcr.rb:317:in `turned_on' - # ./spec/lib/vcr_spec.rb:367:in `block (3 levels) in ' -``` - -I quickly suspected it was a keyword argument issue, but it's far from -obvious to everyone, and even when you are familair with the issue -it doesn't tell you what was expected and what was received. - -I doubt the way I implemented this is ok, but I think it's worth -opening the discussion - -``` - 2) VCR.turned_on passes options through to .turn_off! - Failure/Error: turn_off!(options) - - VCR received :turn_off! with unexpected arguments - expected: ({:ignore_cassettes=>true}) (keyword arguments) - got: ({:ignore_cassettes=>true}) (options hash) - # ./lib/vcr.rb:317:in `turned_on' - # ./spec/lib/vcr_spec.rb:367:in `block (3 levels) in ' -``` ---- - lib/rspec/mocks/error_generator.rb | 11 ++++++++++ - spec/rspec/mocks/diffing_spec.rb | 33 ++++++++++++++++++++++++++++++ - 2 files changed, 44 insertions(+) - -diff --git a/lib/rspec/mocks/error_generator.rb b/lib/rspec/mocks/error_generator.rb -index 9bf0984f3..42ff35283 100644 ---- a/lib/rspec/mocks/error_generator.rb -+++ b/lib/rspec/mocks/error_generator.rb -@@ -268,6 +268,17 @@ def unexpected_arguments_message(expected_args_string, actual_args_string) - def error_message(expectation, args_for_multiple_calls) - expected_args = format_args(expectation.expected_args) - actual_args = format_received_args(args_for_multiple_calls) -+ -+ if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash? && expected_args == actual_args -+ expected_hash = expectation.expected_args.last -+ actual_hash = args_for_multiple_calls.last.last -+ if Hash === expected_hash && Hash === actual_hash && -+ (Hash.ruby2_keywords_hash?(expected_hash) != Hash.ruby2_keywords_hash?(actual_hash)) -+ actual_args += Hash.ruby2_keywords_hash?(actual_hash) ? " (keyword arguments)" : " (options hash)" -+ expected_args += Hash.ruby2_keywords_hash?(expected_hash) ? " (keyword arguments)" : " (options hash)" -+ end -+ end -+ - message = default_error_message(expectation, expected_args, actual_args) - - if args_for_multiple_calls.one? -diff --git a/spec/rspec/mocks/diffing_spec.rb b/spec/rspec/mocks/diffing_spec.rb -index 3b1f91edf..e17aabcd3 100644 ---- a/spec/rspec/mocks/diffing_spec.rb -+++ b/spec/rspec/mocks/diffing_spec.rb -@@ -83,6 +83,39 @@ - end - end - -+ if RSpec::Support::RubyFeatures.distincts_kw_args_from_positional_hash? -+ eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 -+ it "print a diff when keyword argument were expected but got an option hash (using splat)" do -+ with_unfulfilled_double do |d| -+ expect(d).to receive(:foo).with(**expected_hash) -+ expect { -+ d.foo(expected_hash) -+ }.to fail_with( -+ "# received :foo with unexpected arguments\n" \ -+ " expected: ({:baz=>:quz, :foo=>:bar}) (keyword arguments)\n" \ -+ " got: ({:baz=>:quz, :foo=>:bar}) (options hash)" -+ ) -+ end -+ end -+ RUBY -+ -+ eval <<-'RUBY', nil, __FILE__, __LINE__ + 1 -+ it "print a diff when keyword argument were expected but got an option hash (literal)" do -+ with_unfulfilled_double do |d| -+ expect(d).to receive(:foo).with(:positional, keyword: 1) -+ expect { -+ options = { keyword: 1 } -+ d.foo(:positional, options) -+ }.to fail_with( -+ "# received :foo with unexpected arguments\n" \ -+ " expected: (:positional, {:keyword=>1}) (keyword arguments)\n" \ -+ " got: (:positional, {:keyword=>1}) (options hash)" -+ ) -+ end -+ end -+ RUBY -+ end -+ - if RUBY_VERSION.to_f < 1.9 - # Ruby 1.8 hashes are not ordered, but `#inspect` on a particular unchanged - # hash instance should return consistent output. However, on Travis that does diff --git a/rubygem-rspec-mocks.spec b/rubygem-rspec-mocks.spec index d43479d..2a2f1da 100644 --- a/rubygem-rspec-mocks.spec +++ b/rubygem-rspec-mocks.spec @@ -1,9 +1,9 @@ -%global majorver 3.12.0 +%global majorver 3.13.7 #%%global preminorver .rc6 %global rpmminorver .%(echo %preminorver | sed -e 's|^\\.\\.*||') %global fullver %{majorver}%{?preminorver} -%global fedorarel 2 +%global baserelease 2 %global gem_name rspec-mocks @@ -14,31 +14,30 @@ Summary: RSpec's 'test double' framework (mocks and stubs) Name: rubygem-%{gem_name} Version: %{majorver} -Release: %{?preminorver:0.}%{fedorarel}%{?preminorver:%{rpmminorver}}%{?dist} +Release: %{?preminorver:0.}%{baserelease}%{?preminorver:%{rpmminorver}}%{?dist} +# SPDX confirmed License: MIT -URL: http://github.com/rspec/rspec-mocks +URL: https://rspec.info Source0: https://rubygems.org/gems/%{gem_name}-%{fullver}.gem # %%{SOURCE2} %%{name} %%{version} Source1: rubygem-%{gem_name}-%{version}-full.tar.gz Source2: rspec-related-create-full-tarball.sh -# https://github.com/rspec/rspec-mocks/commit/e931e818b577172b89fb4583fc336fbcd25df36b -# The above is in 3.12.x branch, not in 3.11.x branch -Patch1: rubygem-rspec-mocks-3.12.0-display_keyword_hashes.patch -# ... and related to the above, and commit 66250dc1819f9435e5f584064067e7f05a9afe72 -Patch2: rubygem-rspec-mocks-3.12.0-display_keyword_hashes-additional.patch +# https://github.com/rspec/rspec/pull/282/commits/939c4799993b7ff7e524fac701ae6490772ca6de +# Skip mock for ruby4_0 Kernel#inspect +Patch0: rspec-mocks-pr282-skip-mock-for-ruby4_0-inspect.patch -#BuildRequires: ruby(release) BuildRequires: rubygems-devel %if %{without bootstrap} # rspec BuildRequires: rubygem(rspec) -BuildRequires: rubygem(thread_order) BuildRequires: rubygem(rake) +%if %{undefined rhel} # cucumber BuildRequires: rubygem(aruba) BuildRequires: rubygem(cucumber) BuildRequires: rubygem(minitest) +%endif BuildRequires: git %endif BuildArch: noarch @@ -59,11 +58,7 @@ This package contains documentation for %{name}. gem unpack %{SOURCE0} %setup -q -D -T -n %{gem_name}-%{version} -b 1 -%if 0%{?fedora} <= 37 -# Revert "display_keyword_hashes" for now on Fedora 37 -%patch1 -p1 -R -%patch2 -p1 -R -%endif +%patch -P0 -p2 # Cucumber 7 syntax change sed -i cucumber.yml -e "s|~@wip|not @wip|" @@ -84,14 +79,32 @@ cp -a .%{gem_dir}/* \ rm -f %{buildroot}%{gem_instdir}/{.document,.yardopts} %check -%if %{without bootstrap} +%if %{with bootstrap} +# Don't do actual check +exit 0 +%endif + +%if %{defined rhel} +# avoid aruba dep on RHEL, but tests fail if files are removed entirely +echo -n > spec/integration/rails_support_spec.rb +echo -n > spec/support/aruba.rb +%else +# Don't call bundler +sed -i spec/integration/rails_support_spec.rb \ + -e 's|bundle exec rspec|rspec|' +%endif + # library_wide_checks.rb needs UTF-8 LANG=C.UTF-8 export RUBYLIB=$(pwd)/lib rspec spec/ + +%if 0%{?rhel} +# Don't do cucumber test +exit 0 +%endif export CUCUMBER_PUBLISH_QUIET=true cucumber -%endif %files %dir %{gem_instdir} @@ -109,6 +122,75 @@ cucumber %{gem_docdir} %changelog +* Tue Dec 02 2025 Mamoru TASAKA - 3.13.7-2 +- Backport upstream patch to skip mock for Kernel#inspect on ruby4_0 + +* Mon Nov 24 2025 Mamoru TASAKA - 3.13.7-1 +- 3.13.7 + +* Fri Oct 17 2025 Mamoru TASAKA - 3.13.6-1 +- 3.13.6 + +* Fri Jul 25 2025 Fedora Release Engineering - 3.13.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + +* Thu May 29 2025 Mamoru TASAKA - 3.13.5-1 +- 3.13.5 + +* Thu May 15 2025 Mamoru TASAKA - 3.13.4-1 +- 3.13.4 + +* Sat Jan 18 2025 Fedora Release Engineering - 3.13.2-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + +* Sun Dec 29 2024 Mamoru TASAKA - 3.13.2-3 +- Coordinate with rspec-support change wrt ruby34 hash inspect support + +* Wed Nov 06 2024 Mamoru TASAKA - 3.13.2-2 +- Backport upstream patch to support ruby34 formatting + +* Thu Oct 03 2024 Mamoru TASAKA - 3.13.2-1 +- 3.13.2 + +* Fri Jul 19 2024 Fedora Release Engineering - 3.13.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Thu May 09 2024 Mamoru TASAKA - 3.13.1-1 +- 3.13.1 + +* Thu Apr 18 2024 Jun Aruga - 3.13.0-2 +- Remove unused thread_order build dependency + +* Fri Feb 09 2024 Mamoru TASAKA - 3.13.0-1 +- 3.13.0 + +* Fri Jan 26 2024 Fedora Release Engineering - 3.12.6-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Fri Jul 21 2023 Fedora Release Engineering - 3.12.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Sun Jul 16 2023 Mamoru TASAKA - 3.12.6-1 +- 3.12.6 + +* Sat Apr 1 2023 Mamoru TASAKA - 3.12.5-1 +- 3.12.5 + +* Tue Mar 14 2023 Mamoru TASAKA - 3.12.4-1 +- 3.12.4 + +* Thu Mar 09 2023 Yaakov Selkowitz - 3.12.3-2 +- Disable unwanted dependencies in RHEL builds + +* Thu Feb 16 2023 Mamoru TASAKA - 3.12.3-1 +- 3.12.3 + +* Fri Jan 20 2023 Fedora Release Engineering - 3.12.0-3.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Fri Dec 2 2022 Mamoru TASAKA - 3.12.0-3 +- Backport upstream reviewing patch for ruby32 ruby2_keywords treatment change + * Thu Nov 3 2022 Mamoru TASAKA - 3.12.0-2 - On Fedora 37, remove "Display keyword hashes" feature for now (On Fedora 38, this is effective) diff --git a/sources b/sources index 10bb7fa..38528a1 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (rspec-mocks-3.12.0.gem) = eb4a54ac73736e2648c8c14cac1362bafd59452ca54e18f4feb9caa5c5412a449c1cdd9909bd8bfb17f3bcb83c189ab722cbdd409b3942c09f12f427742fd964 -SHA512 (rubygem-rspec-mocks-3.12.0-full.tar.gz) = 808d6fd1b0e71e2ab026650a3fb142a3d806d8f54183f08b379cc20b789982ec1dca791535dcf29ea3f1954909a75b83291397479fe87f1054123a0a5411cdd6 +SHA512 (rspec-mocks-3.13.7.gem) = fa30824f1d7ab82e2c0d1cde1f076cb84b9a9e1e9e7292e33bcfda934468a50f2b59a1dc539137be14ad5b86465ed6fa12c32af2e3a79992c3ce5d278072861c +SHA512 (rubygem-rspec-mocks-3.13.7-full.tar.gz) = 7666b07e6b9806e36d53ede810c6efc0ceb57bc554c96e0fdf44efbfd9dd027a8e999ce942d20bf46f93f93bfae1a88c7ffd0bfbf2cdf08601093a98218a059a