diff --git a/lib/rspec/mocks/deprecation.rb b/lib/rspec/mocks/deprecation.rb deleted file mode 100644 index e56ec6425..000000000 --- a/lib/rspec/mocks/deprecation.rb +++ /dev/null @@ -1,18 +0,0 @@ -module RSpec - module Mocks - module Deprecation - # @private - # - # Used internally to print deprecation warnings - def deprecate(deprecated, options={}) - message = "DEPRECATION: #{deprecated} is deprecated." - message << " Use #{options[:replacement]} instead." if options[:replacement] - message << " Called from #{CallerFilter.first_non_rspec_line}." - warn message - end - end - end - - extend(Mocks::Deprecation) unless respond_to?(:deprecate) -end - diff --git a/lib/rspec/mocks/framework.rb b/lib/rspec/mocks/framework.rb index f6e92a330..adeabb4cb 100644 --- a/lib/rspec/mocks/framework.rb +++ b/lib/rspec/mocks/framework.rb @@ -3,7 +3,7 @@ # object in the system. require 'rspec/mocks/caller_filter' unless defined?(::RSpec::CallerFilter) -require 'rspec/mocks/deprecation' +require 'rspec/mocks/warnings' require 'rspec/mocks/instance_method_stasher' require 'rspec/mocks/method_double' require 'rspec/mocks/argument_matchers' diff --git a/lib/rspec/mocks/message_expectation.rb b/lib/rspec/mocks/message_expectation.rb index 5ed900214..447f3609b 100644 --- a/lib/rspec/mocks/message_expectation.rb +++ b/lib/rspec/mocks/message_expectation.rb @@ -149,6 +149,9 @@ def and_call_original if RSpec::Mocks::TestDouble === @method_double.object @error_generator.raise_only_valid_on_a_partial_mock(:and_call_original) else + if implementation.inner_action + RSpec.warning("You're overriding a previous implementation for this stub") + end @implementation = AndCallOriginalImplementation.new(@method_double.original_method) @yield_receiver_to_implementation_block = false end @@ -501,6 +504,7 @@ def initial_implementation_action=(action) end def inner_implementation_action=(action) + RSpec.warning("You're overriding a previous implementation for this stub") if implementation.inner_action implementation.inner_action = action if action end @@ -597,6 +601,10 @@ def present? true end + def inner_action + true + end + def call(*args, &block) @method.call(*args, &block) end diff --git a/lib/rspec/mocks/warnings.rb b/lib/rspec/mocks/warnings.rb new file mode 100644 index 000000000..168bee0a3 --- /dev/null +++ b/lib/rspec/mocks/warnings.rb @@ -0,0 +1,31 @@ +module RSpec + + unless respond_to?(:deprecate) + # @private + # + # Used internally to print deprecation warnings + def self.deprecate(deprecated, options = {}) + warn_with "DEPRECATION: #{deprecated} is deprecated.", options + end + end + + unless respond_to?(:warning) && respond_to?(:warn_with) + # @private + # + # Used internally to print deprecation warnings + def self.warning(text, options={}) + warn_with "WARNING: #{text}.", options + end + + # @private + # + # Used internally to longer warnings + def self.warn_with(message, options = {}) + message << " Use #{options[:replacement]} instead." if options[:replacement] + message << " Called from #{CallerFilter.first_non_rspec_line}." + ::Kernel.warn message + end + end + +end + diff --git a/spec/rspec/mocks/and_call_original_spec.rb b/spec/rspec/mocks/and_call_original_spec.rb index 0cced0784..0c85e3fdc 100644 --- a/spec/rspec/mocks/and_call_original_spec.rb +++ b/spec/rspec/mocks/and_call_original_spec.rb @@ -22,7 +22,7 @@ def self.new_instance let(:instance) { klass.new } it 'passes the received message through to the original method' do - instance.should_receive(:meth_1).and_call_original + expect(instance).to receive(:meth_1).and_call_original expect(instance.meth_1).to eq(:original) end @@ -33,19 +33,25 @@ def self.new_instance end it 'passes args and blocks through to the original method' do - instance.should_receive(:meth_2).and_call_original + expect(instance).to receive(:meth_2).and_call_original value = instance.meth_2(:submitted_arg) { |a, b| [a, b] } expect(value).to eq([:submitted_arg, :additional_yielded_arg]) end it 'errors when you pass through the wrong number of args' do - instance.stub(:meth_1).and_call_original - instance.stub(:meth_2).and_call_original + expect(instance).to receive(:meth_1).and_call_original + expect(instance).to receive(:meth_2).and_call_original expect { instance.meth_1 :a }.to raise_error ArgumentError expect { instance.meth_2 {} }.to raise_error ArgumentError expect { instance.meth_2(:a, :b) {} }.to raise_error ArgumentError end + it 'warns when you override an existing implementation' do + expect(RSpec).to receive(:warning).with /overriding a previous implementation/ + expect(instance).to receive(:meth_1) { true }.and_call_original + instance.meth_1 + end + context "for singleton methods" do it 'works' do def instance.foo; :bar; end diff --git a/spec/rspec/mocks/combining_implementation_instructions_spec.rb b/spec/rspec/mocks/combining_implementation_instructions_spec.rb index 7904268b9..aa06939c1 100644 --- a/spec/rspec/mocks/combining_implementation_instructions_spec.rb +++ b/spec/rspec/mocks/combining_implementation_instructions_spec.rb @@ -159,6 +159,7 @@ def verify_combined_implementation end it 'allows the inner implementation block to be overriden' do + allow(RSpec).to receive(:warning) dbl = double stubbed_double = dbl.stub(:foo) @@ -169,6 +170,11 @@ def verify_combined_implementation expect(dbl.foo(:arg)).to eq(:at_least_block) end + it 'warns when the inner implementation block is overriden' do + expect(RSpec).to receive(:warning).with /overriding a previous implementation/ + double.stub(:foo).with(:arg) { :with_block }.at_least(:once) { :at_least_block } + end + it 'can combine and_call_original, with, and_return' do obj = Struct.new(:value).new('original') obj.stub(:value).and_call_original @@ -178,6 +184,7 @@ def verify_combined_implementation end it 'raises an error if `and_call_original` is followed by any other instructions' do + allow(RSpec).to receive(:warning) dbl = [1, 2, 3] stubbed = dbl.stub(:size) stubbed.and_call_original