rspec-mocks 2.8.0.rc1 → 2.8.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,11 @@
1
1
  module RSpec
2
2
  module Mocks
3
+ # @private
3
4
  class MethodDouble < Hash
5
+ # @private
4
6
  attr_reader :method_name
5
7
 
8
+ # @private
6
9
  def initialize(object, method_name, proxy)
7
10
  @method_name = method_name
8
11
  @object = object
@@ -12,14 +15,17 @@ module RSpec
12
15
  store(:stubs, [])
13
16
  end
14
17
 
18
+ # @private
15
19
  def expectations
16
20
  self[:expectations]
17
21
  end
18
22
 
23
+ # @private
19
24
  def stubs
20
25
  self[:stubs]
21
26
  end
22
27
 
28
+ # @private
23
29
  def visibility
24
30
  if Mock === @object
25
31
  'public'
@@ -32,18 +38,22 @@ module RSpec
32
38
  end
33
39
  end
34
40
 
41
+ # @private
35
42
  def object_singleton_class
36
43
  class << @object; self; end
37
44
  end
38
45
 
46
+ # @private
39
47
  def obfuscate(method_name)
40
48
  "obfuscated_by_rspec_mocks__#{method_name}"
41
49
  end
42
50
 
51
+ # @private
43
52
  def stashed_method_name
44
53
  obfuscate(method_name)
45
54
  end
46
55
 
56
+ # @private
47
57
  def object_responds_to?(method_name)
48
58
  if @proxy.already_proxied_respond_to?
49
59
  @object.__send__(obfuscate(:respond_to?), method_name)
@@ -54,6 +64,7 @@ module RSpec
54
64
  end
55
65
  end
56
66
 
67
+ # @private
57
68
  def configure_method
58
69
  RSpec::Mocks::space.add(@object) if RSpec::Mocks::space
59
70
  warn_if_nil_class
@@ -63,6 +74,7 @@ module RSpec
63
74
  end
64
75
  end
65
76
 
77
+ # @private
66
78
  def stash_original_method
67
79
  stashed = stashed_method_name
68
80
  orig = @method_name
@@ -72,6 +84,7 @@ module RSpec
72
84
  @stashed = true
73
85
  end
74
86
 
87
+ # @private
75
88
  def define_proxy_method
76
89
  method_name = @method_name
77
90
  visibility_for_method = "#{visibility} :#{method_name}"
@@ -79,10 +92,11 @@ module RSpec
79
92
  def #{method_name}(*args, &block)
80
93
  __mock_proxy.message_received :#{method_name}, *args, &block
81
94
  end
82
- #{visibility_for_method}
95
+ #{visibility_for_method}
83
96
  EOF
84
97
  end
85
98
 
99
+ # @private
86
100
  def restore_original_method
87
101
  if @stashed
88
102
  method_name = @method_name
@@ -98,32 +112,37 @@ module RSpec
98
112
  end
99
113
  end
100
114
 
115
+ # @private
101
116
  def verify
102
117
  expectations.each {|e| e.verify_messages_received}
103
118
  end
104
119
 
120
+ # @private
105
121
  def reset
106
122
  reset_nil_expectations_warning
107
123
  restore_original_method
108
124
  clear
109
125
  end
110
126
 
127
+ # @private
111
128
  def clear
112
129
  expectations.clear
113
130
  stubs.clear
114
131
  end
115
132
 
133
+ # @private
116
134
  def add_expectation(error_generator, expectation_ordering, expected_from, opts, &block)
117
135
  configure_method
118
136
  expectation = if existing_stub = stubs.first
119
- existing_stub.build_child(expected_from, block, 1, opts)
120
- else
121
- MessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, block, 1, opts)
122
- end
137
+ existing_stub.build_child(expected_from, block, 1, opts)
138
+ else
139
+ MessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, block, 1, opts)
140
+ end
123
141
  expectations << expectation
124
142
  expectation
125
143
  end
126
144
 
145
+ # @private
127
146
  def add_negative_expectation(error_generator, expectation_ordering, expected_from, &implementation)
128
147
  configure_method
129
148
  expectation = NegativeMessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, implementation)
@@ -131,32 +150,38 @@ module RSpec
131
150
  expectation
132
151
  end
133
152
 
153
+ # @private
134
154
  def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation)
135
155
  configure_method
136
156
  stub = MessageExpectation.new(error_generator, expectation_ordering, expected_from, @method_name, nil, :any, opts, &implementation)
137
157
  stubs.unshift stub
138
158
  stub
139
159
  end
140
-
160
+
161
+ # @private
141
162
  def remove_stub
142
163
  raise_method_not_stubbed_error if stubs.empty?
143
164
  expectations.empty? ? reset : stubs.clear
144
165
  end
145
166
 
167
+ # @private
146
168
  def proxy_for_nil_class?
147
169
  @object.nil?
148
170
  end
149
171
 
172
+ # @private
150
173
  def warn_if_nil_class
151
174
  if proxy_for_nil_class? & RSpec::Mocks::Proxy.warn_about_expectations_on_nil
152
175
  Kernel.warn("An expectation of :#{@method_name} was set on nil. Called from #{caller[4]}. Use allow_message_expectations_on_nil to disable warnings.")
153
176
  end
154
177
  end
155
-
178
+
179
+ # @private
156
180
  def raise_method_not_stubbed_error
157
181
  raise MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed"
158
182
  end
159
183
 
184
+ # @private
160
185
  def reset_nil_expectations_warning
161
186
  RSpec::Mocks::Proxy.warn_about_expectations_on_nil = true if proxy_for_nil_class?
162
187
  end
@@ -1,37 +1,82 @@
1
1
  module RSpec
2
2
  module Mocks
3
+ # Methods that are added to every object.
3
4
  module Methods
4
- def should_receive(sym, opts={}, &block)
5
- __mock_proxy.add_message_expectation(opts[:expected_from] || caller(1)[0], sym.to_sym, opts, &block)
5
+ # Sets and expectation that this object should receive a message before
6
+ # the end of the example.
7
+ #
8
+ # @example
9
+ #
10
+ # logger = double('logger')
11
+ # thing_that_logs = ThingThatLogs.new(logger)
12
+ # logger.should_receive(:log)
13
+ # thing_that_logs.do_something_that_logs_a_message
14
+ def should_receive(message, opts={}, &block)
15
+ __mock_proxy.add_message_expectation(opts[:expected_from] || caller(1)[0], message.to_sym, opts, &block)
6
16
  end
7
17
 
8
- def should_not_receive(sym, &block)
9
- __mock_proxy.add_negative_message_expectation(caller(1)[0], sym.to_sym, &block)
18
+ # Sets and expectation that this object should _not_ receive a message
19
+ # during this example.
20
+ def should_not_receive(message, &block)
21
+ __mock_proxy.add_negative_message_expectation(caller(1)[0], message.to_sym, &block)
10
22
  end
11
-
12
- def stub(sym_or_hash, opts={}, &block)
13
- if Hash === sym_or_hash
14
- sym_or_hash.each {|method, value| stub(method).and_return value }
23
+
24
+ # Tells the object to respond to the message with the specified value.
25
+ #
26
+ # @example
27
+ #
28
+ # counter.stub(:count).and_return(37)
29
+ # counter.stub(:count => 37)
30
+ # counter.stub(:count) { 37 }
31
+ def stub(message_or_hash, opts={}, &block)
32
+ if Hash === message_or_hash
33
+ message_or_hash.each {|message, value| stub(message).and_return value }
15
34
  else
16
- __mock_proxy.add_stub(caller(1)[0], sym_or_hash.to_sym, opts, &block)
35
+ __mock_proxy.add_stub(caller(1)[0], message_or_hash.to_sym, opts, &block)
17
36
  end
18
37
  end
19
-
20
- def unstub(sym)
21
- __mock_proxy.remove_stub(sym)
38
+
39
+ # Removes a stub. On a double, the object will no longer respond to
40
+ # `message`. On a real object, the original method (if it exists) is
41
+ # restored.
42
+ #
43
+ # This is rarely used, but can be useful when a stub is set up during a
44
+ # shared `before` hook for the common case, but you want to replace it
45
+ # for a special case.
46
+ def unstub(message)
47
+ __mock_proxy.remove_stub(message)
22
48
  end
23
-
49
+
24
50
  alias_method :stub!, :stub
25
51
  alias_method :unstub!, :unstub
26
-
27
- # Stubs a chain of methods. Especially useful with fluent and/or
28
- # composable interfaces.
52
+
53
+ # @overload stub_chain(method1, method2)
54
+ # @overload stub_chain("method1.method2")
55
+ # @overload stub_chain(method1, method_to_value_hash)
56
+ #
57
+ # Stubs a chain of methods.
58
+ #
59
+ # ## Warning:
60
+ #
61
+ # Chains can be arbitrarily long, which makes it quite painless to
62
+ # violate the Law of Demeter in violent ways, so you should consider any
63
+ # use of `stub_chain` a code smell. Even though not all code smells
64
+ # indicate real problems (think fluent interfaces), `stub_chain` still
65
+ # results in brittle examples. For example, if you write
66
+ # `foo.stub_chain(:bar, :baz => 37)` in a spec and then the
67
+ # implementation calls `foo.baz.bar`, the stub will not work.
29
68
  #
30
- # == Examples
69
+ # @example
31
70
  #
32
- # double.stub_chain("foo.bar") { :baz }
33
- # double.stub_chain(:foo, :bar) { :baz }
34
- # Article.stub_chain("recent.published") { [Article.new] }
71
+ # double.stub_chain("foo.bar") { :baz }
72
+ # double.stub_chain(:foo, :bar => :baz)
73
+ # double.stub_chain(:foo, :bar) { :baz }
74
+ #
75
+ # # Given any of ^^ these three forms ^^:
76
+ # double.foo.bar # => :baz
77
+ #
78
+ # # Common use in Rails/ActiveRecord:
79
+ # Article.stub_chain("recent.published") { [Article.new] }
35
80
  def stub_chain(*chain, &blk)
36
81
  chain, blk = format_chain(*chain, &blk)
37
82
  if chain.length > 1
@@ -47,26 +92,33 @@ module RSpec
47
92
  stub(chain.shift, &blk)
48
93
  end
49
94
  end
50
-
95
+
96
+ # Tells the object to respond to all messages. If specific stub values
97
+ # are declared, they'll work as expected. If not, the receiver is
98
+ # returned.
99
+ def as_null_object
100
+ __mock_proxy.as_null_object
101
+ end
102
+
103
+ # Returns true if this object has received `as_null_object`
104
+ def null_object?
105
+ __mock_proxy.null_object?
106
+ end
107
+
108
+ # @private
51
109
  def received_message?(sym, *args, &block)
52
110
  __mock_proxy.received_message?(sym.to_sym, *args, &block)
53
111
  end
54
-
112
+
113
+ # @private
55
114
  def rspec_verify
56
115
  __mock_proxy.verify
57
116
  end
58
117
 
118
+ # @private
59
119
  def rspec_reset
60
120
  __mock_proxy.reset
61
121
  end
62
-
63
- def as_null_object
64
- __mock_proxy.as_null_object
65
- end
66
-
67
- def null_object?
68
- __mock_proxy.null_object?
69
- end
70
122
 
71
123
  private
72
124
 
@@ -3,8 +3,8 @@ module RSpec
3
3
  class Mock
4
4
  include Methods
5
5
 
6
- # Creates a new test double with a +name+ (that will be used in error messages
7
- # only)
6
+ # Creates a new test double with a `name` (that will be used in error
7
+ # messages only)
8
8
  def initialize(name=nil, stubs_and_options={})
9
9
  if name.is_a?(Hash) && stubs_and_options.empty?
10
10
  stubs_and_options = name
@@ -24,18 +24,21 @@ module RSpec
24
24
  other == __mock_proxy
25
25
  end
26
26
 
27
+ # @private
27
28
  def inspect
28
29
  "#<#{self.class}:#{sprintf '0x%x', self.object_id} @name=#{@name.inspect}>"
29
30
  end
30
31
 
32
+ # @private
31
33
  def to_s
32
34
  inspect.gsub('<','[').gsub('>',']')
33
35
  end
34
36
 
35
37
  alias_method :to_str, :to_s
36
38
 
39
+ # @private
37
40
  def respond_to?(sym, incl_private=false)
38
- __mock_proxy.null_object? && sym != :to_ary ? true : super
41
+ __mock_proxy.null_object? && sym != :to_ary ? true : super
39
42
  end
40
43
 
41
44
  private
@@ -59,7 +62,7 @@ module RSpec
59
62
  extract_option(stubs_and_options, options, :__declared_as, 'Mock')
60
63
  options
61
64
  end
62
-
65
+
63
66
  def extract_option(source, target, key, default=nil)
64
67
  if source[key]
65
68
  target[key] = source.delete(key)
@@ -76,4 +79,3 @@ module RSpec
76
79
  end
77
80
  end
78
81
  end
79
-
@@ -1,29 +1,33 @@
1
1
  module RSpec
2
2
  module Mocks
3
+ # @private
3
4
  class OrderGroup
4
5
  def initialize error_generator
5
6
  @error_generator = error_generator
6
7
  @ordering = Array.new
7
8
  end
8
-
9
+
10
+ # @private
9
11
  def register(expectation)
10
12
  @ordering << expectation
11
13
  end
12
-
14
+
15
+ # @private
13
16
  def ready_for?(expectation)
14
17
  return @ordering.first == expectation
15
18
  end
16
-
19
+
20
+ # @private
17
21
  def consume
18
22
  @ordering.shift
19
23
  end
20
-
24
+
25
+ # @private
21
26
  def handle_order_constraint expectation
22
27
  return unless @ordering.include? expectation
23
28
  return consume if ready_for?(expectation)
24
29
  @error_generator.raise_out_of_order_error expectation.sym
25
30
  end
26
-
27
31
  end
28
32
  end
29
33
  end
@@ -1,43 +1,51 @@
1
1
  module RSpec
2
2
  module Mocks
3
+ # @private
3
4
  class Proxy
4
5
  class << self
6
+ # @private
5
7
  def warn_about_expectations_on_nil
6
8
  defined?(@warn_about_expectations_on_nil) ? @warn_about_expectations_on_nil : true
7
9
  end
8
-
10
+
11
+ # @private
9
12
  def warn_about_expectations_on_nil=(new_value)
10
13
  @warn_about_expectations_on_nil = new_value
11
14
  end
12
-
15
+
16
+ # @private
13
17
  def allow_message_expectations_on_nil
14
18
  @warn_about_expectations_on_nil = false
15
-
19
+
16
20
  # ensure nil.rspec_verify is called even if an expectation is not set in the example
17
21
  # otherwise the allowance would effect subsequent examples
18
22
  RSpec::Mocks::space.add(nil) unless RSpec::Mocks::space.nil?
19
23
  end
20
24
 
25
+ # @private
21
26
  def allow_message_expectations_on_nil?
22
27
  !warn_about_expectations_on_nil
23
28
  end
24
29
  end
25
30
 
31
+ # @private
26
32
  def initialize(object, name=nil, options={})
27
33
  @object = object
28
34
  @name = name
29
35
  @error_generator = ErrorGenerator.new object, name, options
30
36
  @expectation_ordering = OrderGroup.new @error_generator
31
- @messages_received = []
37
+ @messages_received = []
32
38
  @options = options
33
39
  @already_proxied_respond_to = false
34
40
  @null_object = false
35
41
  end
36
42
 
43
+ # @private
37
44
  def null_object?
38
45
  @null_object
39
46
  end
40
47
 
48
+ # @private
41
49
  # Tells the object to ignore any messages that aren't explicitly set as
42
50
  # stubs or message expectations.
43
51
  def as_null_object
@@ -45,52 +53,64 @@ module RSpec
45
53
  @object
46
54
  end
47
55
 
56
+ # @private
48
57
  def already_proxied_respond_to
49
58
  @already_proxied_respond_to = true
50
59
  end
51
60
 
61
+ # @private
52
62
  def already_proxied_respond_to?
53
63
  @already_proxied_respond_to
54
64
  end
55
65
 
66
+ # @private
56
67
  def add_message_expectation(location, method_name, opts={}, &block)
57
68
  method_double[method_name].add_expectation @error_generator, @expectation_ordering, location, opts, &block
58
69
  end
59
70
 
71
+ # @private
60
72
  def add_negative_message_expectation(location, method_name, &implementation)
61
73
  method_double[method_name].add_negative_expectation @error_generator, @expectation_ordering, location, &implementation
62
74
  end
63
75
 
76
+ # @private
64
77
  def add_stub(location, method_name, opts={}, &implementation)
65
78
  method_double[method_name].add_stub @error_generator, @expectation_ordering, location, opts, &implementation
66
79
  end
67
-
80
+
81
+ # @private
68
82
  def remove_stub(method_name)
69
83
  method_double[method_name].remove_stub
70
84
  end
71
-
85
+
86
+ # @private
72
87
  def verify
73
88
  method_doubles.each {|d| d.verify}
74
89
  ensure
75
90
  reset
76
91
  end
77
92
 
93
+ # @private
78
94
  def reset
79
95
  method_doubles.each {|d| d.reset}
80
96
  end
81
97
 
98
+ # @private
82
99
  def received_message?(method_name, *args, &block)
83
100
  @messages_received.any? {|array| array == [method_name, args, block]}
84
101
  end
85
102
 
103
+ # @private
86
104
  def has_negative_expectation?(method_name)
87
105
  method_double[method_name].expectations.detect {|expectation| expectation.negative_expectation_for?(method_name)}
88
106
  end
89
-
107
+
108
+ # @private
90
109
  def record_message_received(method_name, *args, &block)
91
110
  @messages_received << [method_name, args, block]
92
111
  end
93
112
 
113
+ # @private
94
114
  def message_received(method_name, *args, &block)
95
115
  expectation = find_matching_expectation(method_name, *args)
96
116
  stub = find_matching_method_stub(method_name, *args)
@@ -116,15 +136,17 @@ module RSpec
116
136
  end
117
137
  end
118
138
 
139
+ # @private
119
140
  def raise_unexpected_message_args_error(expectation, *args)
120
141
  @error_generator.raise_unexpected_message_args_error(expectation, *args)
121
142
  end
122
143
 
144
+ # @private
123
145
  def raise_unexpected_message_error(method_name, *args)
124
146
  @error_generator.raise_unexpected_message_error method_name, *args
125
147
  end
126
-
127
- private
148
+
149
+ private
128
150
 
129
151
  def method_double
130
152
  @method_double ||= Hash.new {|h,k|
@@ -135,10 +157,10 @@ module RSpec
135
157
  def method_doubles
136
158
  method_double.values
137
159
  end
138
-
160
+
139
161
  def find_matching_expectation(method_name, *args)
140
162
  method_double[method_name].expectations.find {|expectation| expectation.matches?(method_name, *args) && !expectation.called_max_times?} ||
141
- method_double[method_name].expectations.find {|expectation| expectation.matches?(method_name, *args)}
163
+ method_double[method_name].expectations.find {|expectation| expectation.matches?(method_name, *args)}
142
164
  end
143
165
 
144
166
  def find_almost_matching_expectation(method_name, *args)
@@ -152,7 +174,6 @@ module RSpec
152
174
  def find_almost_matching_stub(method_name, *args)
153
175
  method_double[method_name].stubs.find {|stub| stub.matches_name_but_not_args(method_name, *args)}
154
176
  end
155
-
156
177
  end
157
178
  end
158
179
  end