require 'spec_helper'

module RSpec::Mocks
  describe "PartialMockUsingMocksDirectly" do
    let(:klass) do
      Class.new do
        module MethodMissing
          remove_method :method_missing rescue nil
          def method_missing(m, *a, &b)
            if m == :captured_by_method_missing
              "response generated by method missing"
            else
              super(m, *a, &b)
            end
          end
        end

        extend MethodMissing
        include MethodMissing

        def existing_method
          :original_value
        end

      end
    end

    let(:obj) { klass.new }

    # See http://rubyforge.org/tracker/index.php?func=detail&aid=10263&group_id=797&atid=3149
    # specify "should clear expectations on verify" do
    #     obj.should_receive(:msg)
    #     obj.msg
    #     verify obj
    #     expect {
    #       obj.msg
    #     }.to raise_error(NoMethodError)
    #
    # end
    it "fails when expected message is not received" do
      obj.should_receive(:msg)
      expect {
        verify obj
      }.to raise_error(RSpec::Mocks::MockExpectationError)
    end

    it "fails when message is received with incorrect args" do
      obj.should_receive(:msg).with(:correct_arg)
      expect {
        obj.msg(:incorrect_arg)
      }.to raise_error(RSpec::Mocks::MockExpectationError)
      obj.msg(:correct_arg)
    end

    it "passes when expected message is received" do
      obj.should_receive(:msg)
      obj.msg
      verify obj
    end

    it "passes when message is received with correct args" do
      obj.should_receive(:msg).with(:correct_arg)
      obj.msg(:correct_arg)
      verify obj
    end

    it "restores the original method if it existed" do
      expect(obj.existing_method).to equal(:original_value)
      obj.should_receive(:existing_method).and_return(:mock_value)
      expect(obj.existing_method).to equal(:mock_value)
      verify obj
      expect(obj.existing_method).to equal(:original_value)
    end

    context "with an instance method handled by method_missing" do
      it "restores the original behavior" do
        expect(obj.captured_by_method_missing).to eq("response generated by method missing")
        obj.stub(:captured_by_method_missing) { "foo" }
        expect(obj.captured_by_method_missing).to eq("foo")
        reset obj
        expect(obj.captured_by_method_missing).to eq("response generated by method missing")
      end
    end

    context "with a class method handled by method_missing" do
      it "restores the original behavior" do
        expect(klass.captured_by_method_missing).to eq("response generated by method missing")
        klass.stub(:captured_by_method_missing) { "foo" }
        expect(klass.captured_by_method_missing).to eq("foo")
        reset klass
        expect(klass.captured_by_method_missing).to eq("response generated by method missing")
      end
    end
  end
end
