rr 0.10.5 → 0.10.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,8 @@
1
+ - Added MIT license
2
+ - Fixed Bug - dont_allow doesn't work when it follows stub (http://github.com/btakita/rr/issues#issue/20)
3
+ - Fixed exception with DoubleInjections on proxy objects (http://github.com/btakita/rr/issues#issue/24)
4
+ - Fixed Bug - Can't stub attribute methods on a BelongsToAssociation (http://github.com/btakita/rr/issues#issue/24)
5
+
1
6
  0.10.5
2
7
  - Fixed issues with Ruby 1.9
3
8
  - Fixed stack overflow caused by double include in Test::Unit adapter [http://github.com/btakita/rr/issues#issue/16]. Identified by Dave Myron (http://github.com/contentfree)
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Brian Takita
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -327,8 +327,8 @@ RR::WildcardMatchers for details.
327
327
  mock(object).method_name(anything).times(any_times) {return_value}
328
328
 
329
329
  == Special Thanks To
330
- With any development effort, there are countless people who have contributed
331
- to making it possible. We all are standing on the shoulders of giants.
330
+ With any development effort, there are countless people who have contributed to making it possible. We all are standing on the shoulders of giants.
331
+ If you have directly contributed to RR and I missed you in this list, please let me know and I will add you. Thanks!
332
332
  * Andreas Haller for patches
333
333
  * Aslak Hellesoy for Developing Rspec
334
334
  * Bryan Helmkamp for patches
@@ -347,9 +347,11 @@ to making it possible. We all are standing on the shoulders of giants.
347
347
  * Matthew O'Connor for patches and pairing with me
348
348
  * Michael Niessner for patches and pairing with me
349
349
  * Mike Mangino (from Elevated Rails) for patches and pairing with me
350
+ * Myron Marston for bug reports
350
351
  * Nick Kallen for documentation suggestions, bug reports, and patches
351
352
  * Nathan Sobo for various ideas and inspiration for cleaner and more expressive code
352
353
  * Parker Thompson for pairing with me
353
354
  * Phil Darnowsky for patches
354
355
  * Pivotal Labs for sponsoring RR development
355
356
  * Stephen Baker for Developing Rspec
357
+ * Tatsuya Ono for patches
@@ -1,5 +1,5 @@
1
1
  ---
2
- :patch: 5
3
2
  :build:
4
- :major: 0
5
3
  :minor: 10
4
+ :patch: 6
5
+ :major: 0
data/lib/rr.rb CHANGED
@@ -64,6 +64,7 @@ require "#{dir}/rr/wildcard_matchers/hash_including"
64
64
  require "#{dir}/rr/times_called_matchers/terminal"
65
65
  require "#{dir}/rr/times_called_matchers/non_terminal"
66
66
  require "#{dir}/rr/times_called_matchers/times_called_matcher"
67
+ require "#{dir}/rr/times_called_matchers/never_matcher"
67
68
  require "#{dir}/rr/times_called_matchers/any_times_matcher"
68
69
  require "#{dir}/rr/times_called_matchers/integer_matcher"
69
70
  require "#{dir}/rr/times_called_matchers/range_matcher"
@@ -97,7 +97,7 @@ module RR
97
97
  #
98
98
  # mock(subject).method_name.never
99
99
  def never
100
- @times_matcher = TimesCalledMatchers::IntegerMatcher.new(0)
100
+ @times_matcher = TimesCalledMatchers::NeverMatcher.new
101
101
  self
102
102
  end
103
103
 
@@ -21,7 +21,7 @@ module RR
21
21
  end
22
22
  end
23
23
 
24
- def register_self_at_double_definition_creator
24
+ def register_self_at_double_definition_creator(domain_name)
25
25
  end
26
26
  end
27
27
 
@@ -25,7 +25,6 @@ module RR
25
25
  def do_call
26
26
  definition.never
27
27
  permissive_argument
28
- reimplementation
29
28
  end
30
29
  end
31
30
  end
@@ -19,33 +19,24 @@ module RR
19
19
  if double.exact_match?(*args)
20
20
  matching_doubles << double
21
21
  if double.attempt?
22
- exact_double_is_terminal_or_non_terminal double
22
+ if double.terminal?
23
+ exact_terminal_doubles_to_attempt << double
24
+ else
25
+ exact_non_terminal_doubles_to_attempt << double
26
+ end
23
27
  end
24
28
  elsif double.wildcard_match?(*args)
25
29
  matching_doubles << double
26
30
  if double.attempt?
27
- wildcard_double_is_terminal_or_non_terminal double
31
+ if double.terminal?
32
+ wildcard_terminal_doubles_to_attempt << double
33
+ else
34
+ wildcard_non_terminal_doubles_to_attempt << double
35
+ end
28
36
  end
29
37
  end
30
38
  end
31
39
  self
32
40
  end
33
-
34
- protected
35
- def exact_double_is_terminal_or_non_terminal(double)
36
- if double.terminal?
37
- exact_terminal_doubles_to_attempt << double
38
- else
39
- exact_non_terminal_doubles_to_attempt << double
40
- end
41
- end
42
-
43
- def wildcard_double_is_terminal_or_non_terminal(double)
44
- if double.terminal?
45
- wildcard_terminal_doubles_to_attempt << double
46
- else
47
- wildcard_non_terminal_doubles_to_attempt << double
48
- end
49
- end
50
41
  end
51
42
  end
@@ -28,7 +28,11 @@ module RR
28
28
  def bind
29
29
  if subject_respond_to_method?(method_name)
30
30
  if subject_has_method_defined?(method_name)
31
- bind_method_with_alias
31
+ if subject_is_proxy_for_method?(method_name)
32
+ bind_method
33
+ else
34
+ bind_method_with_alias
35
+ end
32
36
  else
33
37
  space.method_missing_injection(subject)
34
38
  space.singleton_method_added_injection(subject)
@@ -95,6 +99,11 @@ module RR
95
99
  end
96
100
 
97
101
  protected
102
+ def subject_is_proxy_for_method?(method_name)
103
+ method_owner = @subject.method(method_name).owner
104
+ !(subject_class.object_id == method_owner.object_id || subject_class.ancestors.include?(method_owner))
105
+ end
106
+
98
107
  def deferred_bind_method
99
108
  unless subject_has_method_defined?(original_method_alias_name)
100
109
  bind_method_with_alias
@@ -108,13 +117,13 @@ module RR
108
117
  end
109
118
 
110
119
  def bind_method
111
- returns_method = <<-METHOD
120
+ subject = @subject.is_a?(Class) && !@subject.name.empty? ? @subject.name : "self"
121
+ subject_class.class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
112
122
  def #{@method_name}(*args, &block)
113
123
  arguments = MethodArguments.new(args, block)
114
- RR::Space.double_injection(self, :#{@method_name}).dispatch_method(arguments.arguments, arguments.block)
124
+ RR::Space.double_injection(#{subject}, :#{@method_name}).dispatch_method(arguments.arguments, arguments.block)
115
125
  end
116
126
  METHOD
117
- subject_class.class_eval(returns_method, __FILE__, __LINE__ - 5)
118
127
  end
119
128
  end
120
129
  end
@@ -12,11 +12,12 @@ module RR
12
12
  if double
13
13
  double.method_call(args)
14
14
  call_yields
15
- return_value = extract_subject_from_return_value(call_implementation)
15
+ return_value_1 = call_implementation
16
+ return_value_2 = extract_subject_from_return_value(return_value_1)
16
17
  if after_call_proc
17
- extract_subject_from_return_value(after_call_proc.call(return_value))
18
+ extract_subject_from_return_value(after_call_proc.call(return_value_2))
18
19
  else
19
- return_value
20
+ return_value_2
20
21
  end
21
22
  else
22
23
  double_not_found_error
@@ -0,0 +1,23 @@
1
+ module RR
2
+ module TimesCalledMatchers #:nodoc:
3
+ class NeverMatcher < TimesCalledMatcher
4
+ include Terminal
5
+
6
+ def initialize
7
+ super 0
8
+ end
9
+
10
+ def possible_match?(times_called)
11
+ true
12
+ end
13
+
14
+ def matches?(times_called)
15
+ true
16
+ end
17
+
18
+ def attempt?(times_called)
19
+ raise RR::Errors::TimesCalledError, error_message(1)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
2
+
3
+ describe "dont_allow called after stub" do
4
+ context "when the subject method is called" do
5
+ it "raises a TimesCalledError" do
6
+ subject = Object.new
7
+ stub(subject).foobar
8
+ dont_allow(subject).foobar
9
+ lambda do
10
+ subject.foobar
11
+ end.should raise_error(RR::Errors::TimesCalledError)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,183 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
2
+
3
+ describe "mock" do
4
+ attr_reader :subject
5
+ before(:each) do
6
+ @subject = Object.new
7
+ extend RR::Adapters::RRMethods
8
+ end
9
+
10
+ after(:each) do
11
+ RR.reset
12
+ end
13
+
14
+ it "mocks via inline call" do
15
+ mock(subject).to_s {"a value"}
16
+ subject.to_s.should == "a value"
17
+ lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
18
+ end
19
+
20
+ describe ".once.ordered" do
21
+ it "returns the values in the ordered called" do
22
+ mock(subject).to_s {"value 1"}.ordered
23
+ mock(subject).to_s {"value 2"}.twice
24
+ subject.to_s.should == "value 1"
25
+ subject.to_s.should == "value 2"
26
+ subject.to_s.should == "value 2"
27
+ lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
28
+ end
29
+ end
30
+
31
+ context "when the subject is a proxy for the object with the defined method" do
32
+ it "stubs the method on the proxy object" do
33
+ proxy_target = Class.new {def foobar; :original_foobar; end}.new
34
+ proxy = Class.new do
35
+ def initialize(target)
36
+ @target = target
37
+ end
38
+
39
+ instance_methods.each do |m|
40
+ unless m =~ /^_/ || m.to_s == 'object_id' || m.to_s == 'method_missing'
41
+ alias_method "__blank_slated_#{m}", m
42
+ undef_method m
43
+ end
44
+ end
45
+
46
+ def method_missing(method_name, *args, &block)
47
+ @target.send(method_name, *args, &block)
48
+ end
49
+ end.new(proxy_target)
50
+ proxy.methods.should =~ proxy_target.methods
51
+
52
+ mock(proxy).foobar {:new_foobar}
53
+ proxy.foobar.should == :new_foobar
54
+ end
55
+ end
56
+
57
+ it 'allows terse chaining' do
58
+ mock(subject).first(1) {mock(Object.new).second(2) {mock(Object.new).third(3) {4}}}
59
+ subject.first(1).second(2).third(3).should == 4
60
+
61
+ mock(subject).first(1) {mock!.second(2) {mock!.third(3) {4}}}
62
+ subject.first(1).second(2).third(3).should == 4
63
+
64
+ mock(subject).first(1) {mock!.second(2).mock!.third(3) {4}}
65
+ subject.first(1).second(2).third(3).should == 4
66
+
67
+ mock(subject).first(1) {mock!.second(2).mock! {third(3) {4}}}
68
+ subject.first(1).second(2).third(3).should == 4
69
+
70
+ mock(subject).first(1).mock!.second(2).mock!.third(3) {4}
71
+ subject.first(1).second(2).third(3).should == 4
72
+ end
73
+
74
+ it 'allows chaining with proxy' do
75
+ find_return_value = Object.new
76
+ def find_return_value.child
77
+ :the_child
78
+ end
79
+ (class << subject; self; end).class_eval do
80
+ define_method(:find) do |id|
81
+ id == '1' ? find_return_value : raise(ArgumentError)
82
+ end
83
+ end
84
+
85
+ mock.proxy(subject).find('1').mock.proxy!.child
86
+ subject.find('1').child.should == :the_child
87
+ end
88
+
89
+ it 'allows branched chaining' do
90
+ mock(subject).first do
91
+ mock! do |expect|
92
+ expect.branch1 {mock!.branch11 {11}}
93
+ expect.branch2 {mock!.branch22 {22}}
94
+ end
95
+ end
96
+ o = subject.first
97
+ o.branch1.branch11.should == 11
98
+ o.branch2.branch22.should == 22
99
+ end
100
+
101
+ it 'allows chained ordering' do
102
+ mock(subject).to_s {"value 1"}.then.to_s {"value 2"}.twice.then.to_s {"value 3"}.once
103
+ subject.to_s.should == "value 1"
104
+ subject.to_s.should == "value 2"
105
+ subject.to_s.should == "value 2"
106
+ subject.to_s.should == "value 3"
107
+ lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
108
+ end
109
+
110
+ it "mocks via block with argument" do
111
+ mock subject do |c|
112
+ c.to_s {"a value"}
113
+ c.to_sym {:crazy}
114
+ end
115
+ subject.to_s.should == "a value"
116
+ subject.to_sym.should == :crazy
117
+ end
118
+
119
+ it "mocks via block without argument" do
120
+ mock subject do
121
+ to_s {"a value"}
122
+ to_sym {:crazy}
123
+ end
124
+ subject.to_s.should == "a value"
125
+ subject.to_sym.should == :crazy
126
+ end
127
+
128
+ it "has wildcard matchers" do
129
+ mock(subject).foobar(
130
+ is_a(String),
131
+ anything,
132
+ numeric,
133
+ boolean,
134
+ duck_type(:to_s),
135
+ /abc/
136
+ ) {"value 1"}.twice
137
+ subject.foobar(
138
+ 'hello',
139
+ Object.new,
140
+ 99,
141
+ false,
142
+ "My String",
143
+ "Tabcola"
144
+ ).should == "value 1"
145
+ lambda do
146
+ subject.foobar(:failure)
147
+ end.should raise_error( RR::Errors::DoubleNotFoundError )
148
+ end
149
+
150
+ it "mocks methods without letters" do
151
+ mock(subject) == 55
152
+
153
+ subject == 55
154
+ lambda do
155
+ subject == 99
156
+ end.should raise_error(RR::Errors::DoubleNotFoundError)
157
+ end
158
+
159
+ describe "on class method" do
160
+ class SampleClass1
161
+ def self.hello; "hello!"; end
162
+ end
163
+
164
+ class SampleClass2 < SampleClass1; end
165
+
166
+ it "can mock" do
167
+ mock(SampleClass1).hello { "hola!" }
168
+
169
+ SampleClass1.hello.should == "hola!"
170
+ end
171
+
172
+ it "should not break when it is mocked on subclass" do
173
+ mock(SampleClass1).hello { "hi!" }
174
+
175
+ SampleClass2.hello.should == "hi!"
176
+ end
177
+
178
+ it "should not get affected from a previous example" do
179
+ SampleClass2.hello.should == "hello!"
180
+ end
181
+
182
+ end
183
+ end
@@ -0,0 +1,86 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
2
+
3
+ describe "proxy" do
4
+ attr_reader :subject
5
+ before(:each) do
6
+ @subject = Object.new
7
+ extend RR::Adapters::RRMethods
8
+ end
9
+
10
+ after(:each) do
11
+ RR.reset
12
+ end
13
+
14
+ it "proxies via inline call" do
15
+ expected_to_s_value = subject.to_s
16
+ mock.proxy(subject).to_s
17
+ subject.to_s.should == expected_to_s_value
18
+ lambda {subject.to_s}.should raise_error
19
+ end
20
+
21
+ it "proxy allows ordering" do
22
+ def subject.to_s(arg)
23
+ "Original to_s with arg #{arg}"
24
+ end
25
+ mock.proxy(subject).to_s(:foo).ordered
26
+ mock.proxy(subject).to_s(:bar).twice.ordered
27
+
28
+ subject.to_s(:foo).should == "Original to_s with arg foo"
29
+ subject.to_s(:bar).should == "Original to_s with arg bar"
30
+ subject.to_s(:bar).should == "Original to_s with arg bar"
31
+ lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
32
+ end
33
+
34
+ it "proxy allows ordering" do
35
+ def subject.to_s(arg)
36
+ "Original to_s with arg #{arg}"
37
+ end
38
+ mock.proxy(subject).to_s(:foo).ordered
39
+ mock.proxy(subject).to_s(:bar).twice.ordered
40
+
41
+ subject.to_s(:foo).should == "Original to_s with arg foo"
42
+ subject.to_s(:bar).should == "Original to_s with arg bar"
43
+ subject.to_s(:bar).should == "Original to_s with arg bar"
44
+ lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
45
+ end
46
+
47
+ it "proxies via block with argument" do
48
+ def subject.foobar_1(*args)
49
+ :original_value_1
50
+ end
51
+
52
+ def subject.foobar_2
53
+ :original_value_2
54
+ end
55
+
56
+ mock.proxy subject do |c|
57
+ c.foobar_1(1)
58
+ c.foobar_2
59
+ end
60
+ subject.foobar_1(1).should == :original_value_1
61
+ lambda {subject.foobar_1(:blah)}.should raise_error
62
+
63
+ subject.foobar_2.should == :original_value_2
64
+ lambda {subject.foobar_2(:blah)}.should raise_error
65
+ end
66
+
67
+ it "proxies via block without argument" do
68
+ def subject.foobar_1(*args)
69
+ :original_value_1
70
+ end
71
+
72
+ def subject.foobar_2
73
+ :original_value_2
74
+ end
75
+
76
+ mock.proxy subject do
77
+ foobar_1(1)
78
+ foobar_2
79
+ end
80
+ subject.foobar_1(1).should == :original_value_1
81
+ lambda {subject.foobar_1(:blah)}.should raise_error
82
+
83
+ subject.foobar_2.should == :original_value_2
84
+ lambda {subject.foobar_2(:blah)}.should raise_error
85
+ end
86
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
2
+
3
+ describe "spy" do
4
+ attr_reader :subject
5
+ before(:each) do
6
+ @subject = Object.new
7
+ extend RR::Adapters::RRMethods
8
+ end
9
+
10
+ after(:each) do
11
+ RR.reset
12
+ end
13
+
14
+ it "should record all method invocations" do
15
+ subject = Object.new
16
+ def subject.something
17
+ end
18
+
19
+ def subject.something_else
20
+ end
21
+
22
+ spy(subject)
23
+
24
+ subject.something
25
+ subject.something_else
26
+ subject.to_s
27
+
28
+ received(subject).something.call
29
+ received(subject).something_else.call
30
+ received(subject).to_s.call
31
+ end
32
+
33
+ describe "RR recorded_calls" do
34
+ it "should verify method calls after the fact" do
35
+ stub(subject).pig_rabbit
36
+ subject.pig_rabbit("bacon", "bunny meat")
37
+ #subject.should have_received.pig_rabitt("bacon", "bunny meat")
38
+ received(subject).pig_rabbit("bacon", "bunny meat").call
39
+ end
40
+
41
+ it "should verify method calls after the fact" do
42
+ stub(subject).pig_rabbit
43
+ lambda do
44
+ received(subject).pig_rabbit("bacon", "bunny meat").call
45
+ end.should raise_error(RR::Errors::SpyVerificationErrors::SpyVerificationError)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,87 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
2
+
3
+ class StrongSpecFixture
4
+ def method_with_no_arguments
5
+ end
6
+
7
+ def method_with_one_argument(string)
8
+ end
9
+
10
+ def method_with_two_arguments(string, integer)
11
+ end
12
+
13
+ def method_with_three_arguments_including_varargs(string, integer, *args)
14
+ end
15
+
16
+ def method_with_varargs(*args)
17
+ end
18
+ end
19
+
20
+ describe "strong" do
21
+ attr_reader :subject
22
+ before(:each) do
23
+ @subject = Object.new
24
+ extend RR::Adapters::RRMethods
25
+ end
26
+
27
+ after(:each) do
28
+ RR.reset
29
+ end
30
+
31
+ context "when the method does not exist" do
32
+ it "raises an exception" do
33
+ lambda do
34
+ strong.stub(StrongSpecFixture.new).something
35
+ end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
36
+ end
37
+ end
38
+
39
+ context "when the method exists with no arguments" do
40
+ it "does not raise an exception" do
41
+ strong.stub(StrongSpecFixture.new).method_with_no_arguments
42
+ end
43
+ end
44
+
45
+ context "when the method has a different arity" do
46
+ it "raises an exception" do
47
+ lambda do
48
+ strong.stub(StrongSpecFixture.new).method_with_one_argument
49
+ end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
50
+ end
51
+ end
52
+
53
+ context "when the method has accepts a variable number of arguments" do
54
+ it "does not raise an exception" do
55
+ strong.stub(StrongSpecFixture.new).method_with_varargs
56
+ end
57
+ end
58
+
59
+ context "when the method does not provide the required parameters before varargs" do
60
+ it "raises an exception" do
61
+ lambda do
62
+ strong.stub(StrongSpecFixture.new).method_with_three_arguments_including_varargs
63
+ end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
64
+ end
65
+ end
66
+
67
+ context "when the minimum number of parameters are provided" do
68
+ it "does not raise an exception" do
69
+ strong.stub(StrongSpecFixture.new).method_with_three_arguments_including_varargs("one", 2)
70
+ end
71
+ end
72
+
73
+ context "when using instance_of and the method does not exist" do
74
+ it "raises an exception" do
75
+ lambda do
76
+ strong.stub.instance_of(StrongSpecFixture).something
77
+ StrongSpecFixture.new
78
+ end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
79
+ end
80
+ end
81
+
82
+ context "when using instance_of and the method does exist" do
83
+ it "does not raise an exception" do
84
+ strong.stub.instance_of(StrongSpecFixture).method_with_no_arguments
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,126 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
2
+
3
+ class StubSpecFixture
4
+ attr_reader :initialize_arguments
5
+
6
+ def initialize(*args)
7
+ @initialize_arguments = args
8
+ yield if block_given?
9
+ method_run_in_initialize
10
+ end
11
+
12
+ def method_run_in_initialize
13
+
14
+ end
15
+ end
16
+
17
+ describe "stub" do
18
+ attr_reader :subject
19
+ before(:each) do
20
+ @subject = Object.new
21
+ extend RR::Adapters::RRMethods
22
+ end
23
+
24
+ after(:each) do
25
+ RR.reset
26
+ end
27
+
28
+ it "stubs via inline call" do
29
+ stub(subject).to_s {"a value"}
30
+ subject.to_s.should == "a value"
31
+ end
32
+
33
+ describe ".once.ordered" do
34
+ it "returns the values in the ordered called" do
35
+ stub(subject).to_s {"value 1"}.once.ordered
36
+ stub(subject).to_s {"value 2"}.once.ordered
37
+
38
+ subject.to_s.should == "value 1"
39
+ subject.to_s.should == "value 2"
40
+ end
41
+ end
42
+
43
+ context "when the subject is a proxy for the object with the defined method" do
44
+ it "stubs the method on the proxy object" do
45
+ proxy_target = Class.new {def foobar; :original_foobar; end}.new
46
+ proxy = Class.new do
47
+ def initialize(target)
48
+ @target = target
49
+ end
50
+
51
+ instance_methods.each do |m|
52
+ unless m =~ /^_/ || m.to_s == 'object_id' || m.to_s == 'method_missing'
53
+ alias_method "__blank_slated_#{m}", m
54
+ undef_method m
55
+ end
56
+ end
57
+
58
+ def method_missing(method_name, *args, &block)
59
+ @target.send(method_name, *args, &block)
60
+ end
61
+ end.new(proxy_target)
62
+ proxy.methods.should =~ proxy_target.methods
63
+
64
+ stub(proxy).foobar {:new_foobar}
65
+ proxy.foobar.should == :new_foobar
66
+ end
67
+ end
68
+
69
+ it "stubs via block with argument" do
70
+ stub subject do |d|
71
+ d.to_s {"a value"}
72
+ d.to_sym {:crazy}
73
+ end
74
+ subject.to_s.should == "a value"
75
+ subject.to_sym.should == :crazy
76
+ end
77
+
78
+ it "stubs via block without argument" do
79
+ stub subject do
80
+ to_s {"a value"}
81
+ to_sym {:crazy}
82
+ end
83
+ subject.to_s.should == "a value"
84
+ subject.to_sym.should == :crazy
85
+ end
86
+
87
+ it "stubs instance_of" do
88
+ stub.instance_of(StubSpecFixture) do |o|
89
+ o.to_s {"High Level Spec"}
90
+ end
91
+ StubSpecFixture.new.to_s.should == "High Level Spec"
92
+ end
93
+
94
+ it "stubs methods without letters" do
95
+ stub(subject).__send__(:==) {:equality}
96
+ (subject == 55).should == :equality
97
+ end
98
+
99
+ it "stubs methods invoked in #initialize while passing along the #initialize arg" do
100
+ method_run_in_initialize_stubbed = false
101
+ stub.instance_of(StubSpecFixture) do |o|
102
+ o.method_run_in_initialize {method_run_in_initialize_stubbed = true}
103
+ end
104
+ StubSpecFixture.new
105
+ method_run_in_initialize_stubbed.should be_true
106
+ end
107
+
108
+ it "passed the arguments and block passed to #initialize" do
109
+ block_called = false
110
+ stub.instance_of(StubSpecFixture) do |o|
111
+ o.method_run_in_initialize
112
+ end
113
+ instance = StubSpecFixture.new(1, 2) {block_called = true}
114
+ instance.initialize_arguments.should == [1, 2]
115
+ block_called.should be_true
116
+ end
117
+
118
+ context "mock then stub" do
119
+ it "stubs any calls not matching the mock" do
120
+ mock(subject).foobar(3) {:baz3}
121
+ stub(subject).foobar {:baz}
122
+ subject.foobar(3).should == :baz3
123
+ subject.foobar(4).should == :baz
124
+ end
125
+ end
126
+ end
@@ -81,7 +81,7 @@ module RR
81
81
  context "when passed a method_name argument_expectation" do
82
82
  it "creates a mock Double for method" do
83
83
  double_definition = dont_allow(subject, :foobar)
84
- double_definition.times_matcher.should == TimesCalledMatchers::IntegerMatcher.new(0)
84
+ double_definition.times_matcher.should == TimesCalledMatchers::NeverMatcher.new
85
85
  double_definition.argument_expectation.class.should == RR::Expectations::AnyArgumentExpectation
86
86
 
87
87
  lambda do
@@ -111,7 +111,7 @@ module RR
111
111
  context "when passed a subject and a method_name argument_expectation" do
112
112
  it "creates a mock Double for method" do
113
113
  double_definition = creator.dont_allow(subject, :foobar)
114
- double_definition.times_matcher.should == TimesCalledMatchers::IntegerMatcher.new(0)
114
+ double_definition.times_matcher.should == TimesCalledMatchers::NeverMatcher.new
115
115
  double_definition.argument_expectation.class.should == RR::Expectations::AnyArgumentExpectation
116
116
 
117
117
  lambda do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.5
4
+ version: 0.10.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Takita
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-20 00:00:00 -08:00
12
+ date: 2010-02-15 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -24,6 +24,7 @@ extra_rdoc_files:
24
24
  - README.rdoc
25
25
  files:
26
26
  - CHANGES
27
+ - LICENSE
27
28
  - README.rdoc
28
29
  - Rakefile
29
30
  - VERSION.yml
@@ -80,6 +81,7 @@ files:
80
81
  - lib/rr/times_called_matchers/at_least_matcher.rb
81
82
  - lib/rr/times_called_matchers/at_most_matcher.rb
82
83
  - lib/rr/times_called_matchers/integer_matcher.rb
84
+ - lib/rr/times_called_matchers/never_matcher.rb
83
85
  - lib/rr/times_called_matchers/non_terminal.rb
84
86
  - lib/rr/times_called_matchers/proc_matcher.rb
85
87
  - lib/rr/times_called_matchers/range_matcher.rb
@@ -96,9 +98,14 @@ files:
96
98
  - lib/rr/wildcard_matchers/regexp.rb
97
99
  - lib/rr/wildcard_matchers/satisfy.rb
98
100
  - ruby_19_spec.rb
101
+ - spec/api/dont_allow/dont_allow_after_stub_spec.rb
102
+ - spec/api/mock/mock_spec.rb
103
+ - spec/api/proxy/proxy_spec.rb
104
+ - spec/api/spy/spy_spec.rb
105
+ - spec/api/strong/strong_spec.rb
106
+ - spec/api/stub/stub_spec.rb
99
107
  - spec/core_spec_suite.rb
100
108
  - spec/environment_fixture_setup.rb
101
- - spec/high_level_spec.rb
102
109
  - spec/proc_from_block_spec.rb
103
110
  - spec/rr/adapters/rr_methods_argument_matcher_spec.rb
104
111
  - spec/rr/adapters/rr_methods_creator_spec.rb
@@ -192,6 +199,5 @@ specification_version: 3
192
199
  summary: RR (Double Ruby) is a double framework that features a rich selection of double techniques and a terse syntax. http://xunitpatterns.com/Test%20Double.html
193
200
  test_files:
194
201
  - spec/spy_verification_spec.rb
195
- - spec/high_level_spec.rb
196
202
  - spec/rr_spec.rb
197
203
  - spec/proc_from_block_spec.rb
@@ -1,398 +0,0 @@
1
- require File.expand_path("#{File.dirname(__FILE__)}/spec_helper")
2
-
3
- class HighLevelSpec
4
- attr_reader :initialize_arguments
5
-
6
- def initialize(*args)
7
- @initialize_arguments = args
8
- yield if block_given?
9
- method_run_in_initialize
10
- end
11
-
12
- def method_run_in_initialize
13
-
14
- end
15
- end
16
-
17
- describe "RR" do
18
- attr_reader :subject
19
- before(:each) do
20
- @subject = Object.new
21
- extend RR::Adapters::RRMethods
22
- end
23
-
24
- after(:each) do
25
- RR.reset
26
- end
27
-
28
- describe "mock" do
29
- it "mocks via inline call" do
30
- mock(subject).to_s {"a value"}
31
- subject.to_s.should == "a value"
32
- lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
33
- end
34
-
35
- it "allows ordering" do
36
- mock(subject).to_s {"value 1"}.ordered
37
- mock(subject).to_s {"value 2"}.twice
38
- subject.to_s.should == "value 1"
39
- subject.to_s.should == "value 2"
40
- subject.to_s.should == "value 2"
41
- lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
42
- end
43
-
44
- it 'allows terse chaining' do
45
- mock(subject).first(1) {mock(Object.new).second(2) {mock(Object.new).third(3) {4}}}
46
- subject.first(1).second(2).third(3).should == 4
47
-
48
- mock(subject).first(1) {mock!.second(2) {mock!.third(3) {4}}}
49
- subject.first(1).second(2).third(3).should == 4
50
-
51
- mock(subject).first(1) {mock!.second(2).mock!.third(3) {4}}
52
- subject.first(1).second(2).third(3).should == 4
53
-
54
- mock(subject).first(1) {mock!.second(2).mock! {third(3) {4}}}
55
- subject.first(1).second(2).third(3).should == 4
56
-
57
- mock(subject).first(1).mock!.second(2).mock!.third(3) {4}
58
- subject.first(1).second(2).third(3).should == 4
59
- end
60
-
61
- it 'allows chaining with proxy' do
62
- find_return_value = Object.new
63
- def find_return_value.child
64
- :the_child
65
- end
66
- (class << subject; self; end).class_eval do
67
- define_method(:find) do |id|
68
- id == '1' ? find_return_value : raise(ArgumentError)
69
- end
70
- end
71
-
72
- mock.proxy(subject).find('1').mock.proxy!.child
73
- subject.find('1').child.should == :the_child
74
- end
75
-
76
- it 'allows branched chaining' do
77
- mock(subject).first do
78
- mock! do |expect|
79
- expect.branch1 {mock!.branch11 {11}}
80
- expect.branch2 {mock!.branch22 {22}}
81
- end
82
- end
83
- o = subject.first
84
- o.branch1.branch11.should == 11
85
- o.branch2.branch22.should == 22
86
- end
87
-
88
- it 'allows chained ordering' do
89
- mock(subject).to_s {"value 1"}.then.to_s {"value 2"}.twice.then.to_s {"value 3"}.once
90
- subject.to_s.should == "value 1"
91
- subject.to_s.should == "value 2"
92
- subject.to_s.should == "value 2"
93
- subject.to_s.should == "value 3"
94
- lambda {subject.to_s}.should raise_error(RR::Errors::TimesCalledError)
95
- end
96
-
97
- it "mocks via block with argument" do
98
- mock subject do |c|
99
- c.to_s {"a value"}
100
- c.to_sym {:crazy}
101
- end
102
- subject.to_s.should == "a value"
103
- subject.to_sym.should == :crazy
104
- end
105
-
106
- it "mocks via block without argument" do
107
- mock subject do
108
- to_s {"a value"}
109
- to_sym {:crazy}
110
- end
111
- subject.to_s.should == "a value"
112
- subject.to_sym.should == :crazy
113
- end
114
-
115
- it "has wildcard matchers" do
116
- mock(subject).foobar(
117
- is_a(String),
118
- anything,
119
- numeric,
120
- boolean,
121
- duck_type(:to_s),
122
- /abc/
123
- ) {"value 1"}.twice
124
- subject.foobar(
125
- 'hello',
126
- Object.new,
127
- 99,
128
- false,
129
- "My String",
130
- "Tabcola"
131
- ).should == "value 1"
132
- lambda do
133
- subject.foobar(:failure)
134
- end.should raise_error( RR::Errors::DoubleNotFoundError )
135
- end
136
-
137
- it "mocks methods without letters" do
138
- mock(subject) == 55
139
-
140
- subject == 55
141
- lambda do
142
- subject == 99
143
- end.should raise_error(RR::Errors::DoubleNotFoundError)
144
- end
145
- end
146
-
147
- describe "proxy" do
148
- it "proxies via inline call" do
149
- expected_to_s_value = subject.to_s
150
- mock.proxy(subject).to_s
151
- subject.to_s.should == expected_to_s_value
152
- lambda {subject.to_s}.should raise_error
153
- end
154
-
155
- it "proxy allows ordering" do
156
- def subject.to_s(arg)
157
- "Original to_s with arg #{arg}"
158
- end
159
- mock.proxy(subject).to_s(:foo).ordered
160
- mock.proxy(subject).to_s(:bar).twice.ordered
161
-
162
- subject.to_s(:foo).should == "Original to_s with arg foo"
163
- subject.to_s(:bar).should == "Original to_s with arg bar"
164
- subject.to_s(:bar).should == "Original to_s with arg bar"
165
- lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
166
- end
167
-
168
- it "proxy allows ordering" do
169
- def subject.to_s(arg)
170
- "Original to_s with arg #{arg}"
171
- end
172
- mock.proxy(subject).to_s(:foo).ordered
173
- mock.proxy(subject).to_s(:bar).twice.ordered
174
-
175
- subject.to_s(:foo).should == "Original to_s with arg foo"
176
- subject.to_s(:bar).should == "Original to_s with arg bar"
177
- subject.to_s(:bar).should == "Original to_s with arg bar"
178
- lambda {subject.to_s(:bar)}.should raise_error(RR::Errors::TimesCalledError)
179
- end
180
-
181
- it "proxies via block with argument" do
182
- def subject.foobar_1(*args)
183
- :original_value_1
184
- end
185
-
186
- def subject.foobar_2
187
- :original_value_2
188
- end
189
-
190
- mock.proxy subject do |c|
191
- c.foobar_1(1)
192
- c.foobar_2
193
- end
194
- subject.foobar_1(1).should == :original_value_1
195
- lambda {subject.foobar_1(:blah)}.should raise_error
196
-
197
- subject.foobar_2.should == :original_value_2
198
- lambda {subject.foobar_2(:blah)}.should raise_error
199
- end
200
-
201
- it "proxies via block without argument" do
202
- def subject.foobar_1(*args)
203
- :original_value_1
204
- end
205
-
206
- def subject.foobar_2
207
- :original_value_2
208
- end
209
-
210
- mock.proxy subject do
211
- foobar_1(1)
212
- foobar_2
213
- end
214
- subject.foobar_1(1).should == :original_value_1
215
- lambda {subject.foobar_1(:blah)}.should raise_error
216
-
217
- subject.foobar_2.should == :original_value_2
218
- lambda {subject.foobar_2(:blah)}.should raise_error
219
- end
220
- end
221
-
222
- describe "stub" do
223
- it "stubs via inline call" do
224
- stub(subject).to_s {"a value"}
225
- subject.to_s.should == "a value"
226
- end
227
-
228
- it "allows ordering" do
229
- stub(subject).to_s {"value 1"}.once.ordered
230
- stub(subject).to_s {"value 2"}.once.ordered
231
-
232
- subject.to_s.should == "value 1"
233
- subject.to_s.should == "value 2"
234
- end
235
-
236
- it "stubs via block with argument" do
237
- stub subject do |d|
238
- d.to_s {"a value"}
239
- d.to_sym {:crazy}
240
- end
241
- subject.to_s.should == "a value"
242
- subject.to_sym.should == :crazy
243
- end
244
-
245
- it "stubs via block without argument" do
246
- stub subject do
247
- to_s {"a value"}
248
- to_sym {:crazy}
249
- end
250
- subject.to_s.should == "a value"
251
- subject.to_sym.should == :crazy
252
- end
253
-
254
- it "stubs instance_of" do
255
- stub.instance_of(HighLevelSpec) do |o|
256
- o.to_s {"High Level Spec"}
257
- end
258
- HighLevelSpec.new.to_s.should == "High Level Spec"
259
- end
260
-
261
- it "stubs methods without letters" do
262
- stub(subject).__send__(:==) {:equality}
263
- (subject == 55).should == :equality
264
- end
265
-
266
- it "stubs methods invoked in #initialize while passing along the #initialize arg" do
267
- method_run_in_initialize_stubbed = false
268
- stub.instance_of(HighLevelSpec) do |o|
269
- o.method_run_in_initialize {method_run_in_initialize_stubbed = true}
270
- end
271
- HighLevelSpec.new
272
- method_run_in_initialize_stubbed.should be_true
273
- end
274
-
275
- it "passed the arguments and block passed to #initialize" do
276
- block_called = false
277
- stub.instance_of(HighLevelSpec) do |o|
278
- o.method_run_in_initialize
279
- end
280
- instance = HighLevelSpec.new(1, 2) {block_called = true}
281
- instance.initialize_arguments.should == [1, 2]
282
- block_called.should be_true
283
- end
284
- end
285
-
286
- describe "RR recorded_calls" do
287
- it "should verify method calls after the fact" do
288
- stub(subject).pig_rabbit
289
- subject.pig_rabbit("bacon", "bunny meat")
290
- #subject.should have_received.pig_rabitt("bacon", "bunny meat")
291
- received(subject).pig_rabbit("bacon", "bunny meat").call
292
- end
293
-
294
- it "should verify method calls after the fact" do
295
- stub(subject).pig_rabbit
296
- lambda do
297
- received(subject).pig_rabbit("bacon", "bunny meat").call
298
- end.should raise_error(RR::Errors::SpyVerificationErrors::SpyVerificationError)
299
- end
300
- end
301
-
302
- class StrongTestObject
303
- def method_with_no_arguments
304
- end
305
-
306
- def method_with_one_argument(string)
307
- end
308
-
309
- def method_with_two_arguments(string, integer)
310
- end
311
-
312
- def method_with_three_arguments_including_varargs(string, integer, *args)
313
- end
314
-
315
- def method_with_varargs(*args)
316
- end
317
- end
318
-
319
- describe "strong" do
320
- context "when the method does not exist" do
321
- it "raises an exception" do
322
- lambda do
323
- strong.stub(StrongTestObject.new).something
324
- end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
325
- end
326
- end
327
-
328
- context "when the method exists with no arguments" do
329
- it "does not raise an exception" do
330
- strong.stub(StrongTestObject.new).method_with_no_arguments
331
- end
332
- end
333
-
334
- context "when the method has a different arity" do
335
- it "raises an exception" do
336
- lambda do
337
- strong.stub(StrongTestObject.new).method_with_one_argument
338
- end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
339
- end
340
- end
341
-
342
- context "when the method has accepts a variable number of arguments" do
343
- it "does not raise an exception" do
344
- strong.stub(StrongTestObject.new).method_with_varargs
345
- end
346
- end
347
-
348
- context "when the method does not provide the required parameters before varargs" do
349
- it "raises an exception" do
350
- lambda do
351
- strong.stub(StrongTestObject.new).method_with_three_arguments_including_varargs
352
- end.should raise_error(RR::Errors::SubjectHasDifferentArityError)
353
- end
354
- end
355
-
356
- context "when the minimum number of parameters are provided" do
357
- it "does not raise an exception" do
358
- strong.stub(StrongTestObject.new).method_with_three_arguments_including_varargs("one", 2)
359
- end
360
- end
361
-
362
- context "when using instance_of and the method does not exist" do
363
- it "raises an exception" do
364
- lambda do
365
- strong.stub.instance_of(StrongTestObject).something
366
- StrongTestObject.new
367
- end.should raise_error(RR::Errors::SubjectDoesNotImplementMethodError)
368
- end
369
- end
370
-
371
- context "when using instance_of and the method does exist" do
372
- it "does not raise an exception" do
373
- strong.stub.instance_of(StrongTestObject).method_with_no_arguments
374
- end
375
- end
376
- end
377
-
378
- describe "spy" do
379
- it "should record all method invocations" do
380
- subject = Object.new
381
- def subject.something
382
- end
383
-
384
- def subject.something_else
385
- end
386
-
387
- spy(subject)
388
-
389
- subject.something
390
- subject.something_else
391
- subject.to_s
392
-
393
- received(subject).something.call
394
- received(subject).something_else.call
395
- received(subject).to_s.call
396
- end
397
- end
398
- end