72 lines
2.8 KiB
Diff
72 lines
2.8 KiB
Diff
From 363c1e4a56f53ba3dbd00d50889250ab24f005a8 Mon Sep 17 00:00:00 2001
|
|
From: Benoit Daloze <eregontp@gmail.com>
|
|
Date: Thu, 21 Apr 2022 16:10:58 +0200
|
|
Subject: [PATCH] Use a better and more reliable check for whether a method is
|
|
the same as Class#new
|
|
|
|
* See https://bugs.ruby-lang.org/issues/18729#note-5
|
|
---
|
|
lib/rspec/mocks/method_reference.rb | 16 ++++++++++++++--
|
|
spec/rspec/mocks/partial_double_spec.rb | 18 ++++++++++++++++++
|
|
2 files changed, 32 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/lib/rspec/mocks/method_reference.rb b/lib/rspec/mocks/method_reference.rb
|
|
index 026c2c07d..276202563 100644
|
|
--- a/lib/rspec/mocks/method_reference.rb
|
|
+++ b/lib/rspec/mocks/method_reference.rb
|
|
@@ -185,11 +185,23 @@ class ClassNewMethodReference < ObjectMethodReference
|
|
def self.applies_to?(method_name)
|
|
return false unless method_name == :new
|
|
klass = yield
|
|
- return false unless klass.respond_to?(:new, true)
|
|
+ return false unless ::Class === klass && klass.respond_to?(:new, true)
|
|
|
|
# We only want to apply our special logic to normal `new` methods.
|
|
# Methods that the user has monkeyed with should be left as-is.
|
|
- ::RSpec::Support.method_handle_for(klass, :new).owner == ::Class
|
|
+ uses_class_new?(klass)
|
|
+ end
|
|
+
|
|
+ if RUBY_VERSION.to_i >= 3
|
|
+ CLASS_NEW = ::Class.singleton_class.instance_method(:new)
|
|
+
|
|
+ def self.uses_class_new?(klass)
|
|
+ ::RSpec::Support.method_handle_for(klass, :new) == CLASS_NEW.bind(klass)
|
|
+ end
|
|
+ else # Ruby 2's Method#== is too strict
|
|
+ def self.uses_class_new?(klass)
|
|
+ ::RSpec::Support.method_handle_for(klass, :new).owner == ::Class
|
|
+ end
|
|
end
|
|
|
|
def with_signature
|
|
diff --git a/spec/rspec/mocks/partial_double_spec.rb b/spec/rspec/mocks/partial_double_spec.rb
|
|
index 099b15517..ea327e101 100644
|
|
--- a/spec/rspec/mocks/partial_double_spec.rb
|
|
+++ b/spec/rspec/mocks/partial_double_spec.rb
|
|
@@ -622,6 +622,24 @@ class << self
|
|
end
|
|
end
|
|
|
|
+ context "on a class with a twice-aliased `new`" do
|
|
+ it 'uses the method signature from `#initialize` for arg verification' do
|
|
+ if RUBY_VERSION.to_i < 3
|
|
+ pending "Failing due to Ruby 2's Method#== being too strict"
|
|
+ end
|
|
+
|
|
+ subclass = Class.new(klass) do
|
|
+ class << self
|
|
+ alias_method :_new, :new
|
|
+ alias_method :new, :_new
|
|
+ end
|
|
+ end
|
|
+
|
|
+ prevents(/arguments/) { allow(subclass).to receive(:new).with(1) }
|
|
+ allow(subclass).to receive(:new).with(1, 2)
|
|
+ end
|
|
+ end
|
|
+
|
|
context 'on a class that has redefined `self.method`' do
|
|
it 'allows the stubbing of :new' do
|
|
subclass = Class.new(klass) do
|