File: test_double.rb

package info (click to toggle)
ruby-rspec-mocks 2.14.5-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 868 kB
  • ctags: 725
  • sloc: ruby: 8,227; makefile: 4
file content (135 lines) | stat: -rw-r--r-- 4,065 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
module RSpec
  module Mocks
    # Implements the methods needed for a pure test double.  RSpec::Mocks::Mock
    # includes this module, and it is provided for cases where you want a
    # pure test double without subclassing RSpec::Mocks::Mock.
    module TestDouble
      # Extends the TestDouble module onto the given object and
      # initializes it as a test double.
      #
      # @example
      #
      #   module = Module.new
      #   RSpec::Mocks::TestDouble.extend_onto(module, "MyMixin", :foo => "bar")
      #   module.foo  #=> "bar"
      def self.extend_onto(object, name=nil, stubs_and_options={})
        object.extend self
        object.send(:__initialize_as_test_double, name, stubs_and_options)
      end

      # Creates a new test double with a `name` (that will be used in error
      # messages only)
      def initialize(name=nil, stubs_and_options={})
        __initialize_as_test_double(name, stubs_and_options)
      end

      # Tells the object to respond to all messages. If specific stub values
      # are declared, they'll work as expected. If not, the receiver is
      # returned.
      def as_null_object
        @__null_object = true
        __mock_proxy.as_null_object
      end

      # Returns true if this object has received `as_null_object`
      def null_object?
        @__null_object
      end

      # This allows for comparing the mock to other objects that proxy such as
      # ActiveRecords belongs_to proxy objects. By making the other object run
      # the comparison, we're sure the call gets delegated to the proxy
      # target.
      def ==(other)
        other == __mock_proxy
      end

      # @private
      def inspect
        "#<#{self.class}:#{sprintf '0x%x', self.object_id} @name=#{@name.inspect}>"
      end

      # @private
      def to_s
        inspect.gsub('<','[').gsub('>',']')
      end

      alias_method :to_str, :to_s

      # @private
      def respond_to?(message, incl_private=false)
        __mock_proxy.null_object? ? true : super
      end

      # @private
      def __build_mock_proxy
        proxy = Proxy.new(self, @name, @options || {})
        proxy.as_null_object if null_object?
        proxy
      end

    private

      def __initialize_as_test_double(name=nil, stubs_and_options={})
        @__null_object = false

        if name.is_a?(Hash) && stubs_and_options.empty?
          stubs_and_options = name
          @name = nil
        else
          @name = name
        end
        @options = extract_options(stubs_and_options)
        assign_stubs(stubs_and_options)
      end

      def method_missing(message, *args, &block)
        if __mock_proxy.null_object?
          case message
          when :to_int        then return 0
          when :to_a, :to_ary then return nil
          end
        end
        __mock_proxy.record_message_received(message, *args, &block)

        begin
          __mock_proxy.null_object? ? self : super
        rescue NameError
          # Required wrapping doubles in an Array on Ruby 1.9.2
          raise NoMethodError if [:to_a, :to_ary].include? message
          __mock_proxy.raise_unexpected_message_error(message, *args)
        end
      end

      def extract_options(stubs_and_options)
        if stubs_and_options[:null_object]
          @null_object = stubs_and_options.delete(:null_object)
          RSpec.deprecate("double('name', :null_object => true)", :replacement => "double('name').as_null_object")
        end
        options = {}
        extract_option(stubs_and_options, options, :__declared_as, 'Mock')
        options
      end

      def extract_option(source, target, key, default=nil)
        if source[key]
          target[key] = source.delete(key)
        elsif default
          target[key] = default
        end
      end

      def assign_stubs(stubs)
        stubs.each_pair do |message, response|
          Mocks.allow_message(self, message).and_return(response)
        end
      end

    private

      def __mock_proxy
        ::RSpec::Mocks.proxy_for(self)
      end
    end
  end
end