surrogate 0.3.2 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1 +1,13 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new :rspec do |t|
6
+ t.rspec_opts = [
7
+ '--fail-fast',
8
+ '--colour',
9
+ '--format', 'documentation',
10
+ ]
11
+ end
12
+
13
+ task default: :rspec
data/Readme.md CHANGED
@@ -64,13 +64,14 @@ end
64
64
  MockClient.new.request 3 # => ["result1", "result2", "result3"]
65
65
  ```
66
66
 
67
- You don't need a **default if you set the ivar** of the same name
67
+ You don't need a **default if you set the ivar** of the same name (replace `?` with `_p` for predicates, since you can't have question marks in ivar names)
68
68
 
69
69
  ```ruby
70
70
  class MockClient
71
71
  Surrogate.endow self
72
- define(:initialize) { |id| @id = id }
72
+ define(:initialize) { |id| @id, @connected_p = id, true }
73
73
  define :id
74
+ define :connected?
74
75
  end
75
76
  MockClient.new(12).id # => 12
76
77
  ```
@@ -318,7 +319,7 @@ end
318
319
  # doesn't matter that real user has a name as long as it has initialize and id
319
320
  MockUser.should substitute_for User, subset: true
320
321
 
321
- # but now it fails b/c it has no addres
322
+ # but now it fails b/c it has no address
322
323
  MockUser.define :address
323
324
  MockUser.should_not substitute_for User, subset: true
324
325
  ```
@@ -332,7 +333,7 @@ the initializer, you can pass a factory to your class, you can give the class th
332
333
  setter and then override it whenever you feel it is necessary, you can use RSpec's `#stub` method to put
333
334
  it into place.
334
335
 
335
- Personally, I use [Deject](https://rubygems.org/gems/deject) another gem I wrote. For more on why I feel
336
+ Personally, I use [Deject](https://rubygems.org/gems/deject), another gem I wrote. For more on why I feel
336
337
  it is a better solution than the above methods, see it's [readme](https://github.com/JoshCheek/deject/tree/938edc985c65358c074a7c7b7bbf18dc11e9450e#why-write-this).
337
338
 
338
339
 
@@ -346,6 +347,7 @@ Special Thanks
346
347
  ==============
347
348
 
348
349
  * [Kyle Hargraves](https://github.com/pd) for changing the name of his internal gem so that I could take Surrogate
350
+ * [David Chelimsky](http://blog.davidchelimsky.net/) for pairing with me to make Surrogate integrate better with RSpec
349
351
  * [Corey Haines](http://coreyhaines.com/) for pairing on substitutability with me
350
352
  * [Enova](http://www.enovafinancial.com/) for giving me time and motivation to work on this during Enova Labs.
351
353
  * [8th Light](http://8thlight.com/) for giving me time to work on this during our weekly Wazas, and the general encouragement and interest
@@ -361,7 +363,6 @@ TODO
361
363
  Future Features
362
364
  ---------------
363
365
 
364
- * Support all RSpec matchers (hash_including, anything, etc. see them in RSpec::Mocks::ArgumentMatchers)
365
366
  * have some sort of reinitialization that can hook into setup/teardown steps of test suite
366
367
  * Support arity checking as part of substitutability
367
368
  * Support for blocks
@@ -55,7 +55,7 @@ class Surrogate
55
55
  @hijacking_initialize = false
56
56
  end
57
57
  initialize = klass.instance_method :initialize
58
- klass.send :define_method, :initialize do |*args, &block|
58
+ klass.__send__ :define_method, :initialize do |*args, &block|
59
59
  initialize.bind(self).call(*args, &block)
60
60
  end
61
61
  end
@@ -65,7 +65,7 @@ class Surrogate
65
65
  end
66
66
 
67
67
  def remember_invocations_for_instances_of(klass)
68
- klass.send :define_method, :invocations do |method_name|
68
+ klass.__send__ :define_method, :invocations do |method_name|
69
69
  @hatchling.invocations method_name
70
70
  end
71
71
  end
@@ -30,11 +30,11 @@ class Surrogate
30
30
  private
31
31
 
32
32
  def klass_can_define_api_methods
33
- klass.singleton_class.send :define_method, :define, &method(:define)
33
+ klass.singleton_class.__send__ :define_method, :define, &method(:define)
34
34
  end
35
35
 
36
36
  def add_api_method_for(method_name)
37
- klass.send :define_method, method_name do |*args, &block|
37
+ klass.__send__ :define_method, method_name do |*args, &block|
38
38
  @hatchling.invoke_method method_name, args, &block
39
39
  end
40
40
  end
@@ -48,7 +48,7 @@ class Surrogate
48
48
  end
49
49
 
50
50
  def add_helpers_for(method_name, helper_name)
51
- klass.send :define_method, helper_name do |*args, &block|
51
+ klass.__send__ :define_method, helper_name do |*args, &block|
52
52
  @hatchling.prepare_method method_name, args, &block
53
53
  self
54
54
  end
@@ -31,19 +31,28 @@ class Surrogate
31
31
 
32
32
  # maybe these four should be extracted into their own class
33
33
  def has_ivar?(method_name)
34
- instance.instance_variable_defined? "@#{method_name}"
34
+ instance.instance_variable_defined? ivar_for method_name
35
35
  end
36
36
 
37
37
  def set_ivar(method_name, value)
38
- instance.instance_variable_set "@#{method_name}", value
38
+ instance.instance_variable_set ivar_for(method_name), value
39
39
  end
40
40
 
41
41
  def get_ivar(method_name)
42
- instance.instance_variable_get "@#{method_name}"
42
+ instance.instance_variable_get ivar_for method_name
43
43
  end
44
44
 
45
45
  def unset_ivar(method_name)
46
- instance.send :remove_instance_variable, "@#{method_name}"
46
+ instance.__send__ :remove_instance_variable, ivar_for(method_name)
47
+ end
48
+
49
+ def ivar_for(method_name)
50
+ case method_name
51
+ when /\?$/
52
+ "@#{method_name.to_s.chop}_p"
53
+ else
54
+ "@#{method_name}"
55
+ end
47
56
  end
48
57
 
49
58
  private
@@ -50,14 +50,14 @@ class Surrogate
50
50
  end
51
51
 
52
52
  def inspect_arguments(arguments)
53
- inspected_arguments = arguments.map { |argument| MessagesFor.inspect_argument argument }
54
- inspected_arguments << 'no_args' if inspected_arguments.empty?
55
- %Q(`#{inspected_arguments.join ", "}')
53
+ inspected_arguments = arguments.map { |argument| inspect_argument argument }
54
+ inspected_arguments << 'no args' if inspected_arguments.empty?
55
+ "`" << inspected_arguments.join(", ") << "'"
56
56
  end
57
57
 
58
58
  def inspect_argument(to_inspect)
59
- if to_inspect.kind_of? ::RSpec::Mocks::ArgumentMatchers::NoArgsMatcher
60
- "no_args"
59
+ if RSpec.rspec_mocks_loaded? && to_inspect.respond_to?(:description)
60
+ to_inspect.description
61
61
  else
62
62
  to_inspect.inspect
63
63
  end
@@ -67,8 +67,9 @@ class Surrogate
67
67
  end
68
68
 
69
69
 
70
+ # sigh, surely there is a better name!
70
71
  class Handler < Struct.new(:subject, :language_type)
71
- attr_accessor :instance, :message_type
72
+ attr_accessor :instance
72
73
 
73
74
  def message_for(message_category, message_type)
74
75
  MessagesFor.message_for(language_type, message_category, message_type, binding)
@@ -79,7 +80,7 @@ class Surrogate
79
80
  end
80
81
 
81
82
  def message_type
82
- @message_type || :default
83
+ :default
83
84
  end
84
85
 
85
86
  def invocations
@@ -105,23 +106,45 @@ class Surrogate
105
106
  def failure_message_for_should_not
106
107
  message_for :should_not, message_type
107
108
  end
108
- end
109
109
 
110
+ def times(times_invoked)
111
+ # is there a good way to remove these conditionals?
112
+ extend (kind_of?(MatchWithArguments) ? MatchNumTimesWith : MatchNumTimes)
113
+ self.expected_times_invoked = times_invoked
114
+ self
115
+ end
110
116
 
111
- module MatchWithArguments
112
- def self.extended(klass)
113
- klass.message_type = :with
117
+ def with(*arguments)
118
+ extend (kind_of?(MatchNumTimes) ? MatchNumTimesWith : MatchWithArguments)
119
+ self.expected_arguments = arguments
120
+ self
114
121
  end
122
+ end
115
123
 
116
- attr_accessor :expected_arguments
117
124
 
118
- def match? # eventually this will need to get a lot smarter
119
- if expected_arguments.size == 1 && expected_arguments.first.kind_of?(::RSpec::Mocks::ArgumentMatchers::NoArgsMatcher)
120
- invocations.include? []
125
+ module ArgumentComparer
126
+ def args_match?(actual_arguments)
127
+ if RSpec.rspec_mocks_loaded?
128
+ rspec_arg_expectation = ::RSpec::Mocks::ArgumentExpectation.new *expected_arguments
129
+ rspec_arg_expectation.args_match? *actual_arguments
121
130
  else
122
- invocations.include? expected_arguments
131
+ expected_arguments == actual_arguments
123
132
  end
124
133
  end
134
+ end
135
+
136
+ module MatchWithArguments
137
+ include ArgumentComparer
138
+
139
+ attr_accessor :expected_arguments
140
+
141
+ def message_type
142
+ :with
143
+ end
144
+
145
+ def match?
146
+ invocations.any? { |invocation| args_match? invocation }
147
+ end
125
148
 
126
149
  def actual_invocation
127
150
  return message_for :other, :not_invoked if times_invoked.zero?
@@ -132,8 +155,8 @@ class Surrogate
132
155
 
133
156
 
134
157
  module MatchNumTimes
135
- def self.extended(klass)
136
- klass.message_type = :times
158
+ def message_type
159
+ :times
137
160
  end
138
161
 
139
162
  attr_accessor :expected_times_invoked
@@ -145,14 +168,16 @@ class Surrogate
145
168
 
146
169
 
147
170
  module MatchNumTimesWith
148
- def self.extended(klass)
149
- klass.message_type = :with_times
171
+ include ArgumentComparer
172
+
173
+ def message_type
174
+ :with_times
150
175
  end
151
176
 
152
177
  attr_accessor :expected_times_invoked, :expected_arguments
153
178
 
154
179
  def times_invoked_with_expected_args
155
- invocations.select { |invocation| invocation == expected_arguments }.size
180
+ invocations.select { |invocation| args_match? invocation }.size
156
181
  end
157
182
 
158
183
  def match?
@@ -166,75 +191,37 @@ class Surrogate
166
191
  end
167
192
 
168
193
 
194
+ surrogate_matcher = lambda do |use_case, matcher, morphable=false|
195
+ if morphable
196
+ matcher.chain(:times) { |number| use_case.times number }
197
+ matcher.chain(:with) { |*arguments| use_case.with *arguments }
198
+ end
169
199
 
170
-
171
-
172
- # have_been_told_to
173
- ::RSpec::Matchers.define :have_been_told_to do |verb|
174
- use_case = Handler.new verb, :verb
175
-
176
- match do |mocked_instance|
200
+ matcher.match do |mocked_instance|
177
201
  use_case.instance = mocked_instance
178
202
  use_case.match?
179
203
  end
180
204
 
181
- chain :times do |number|
182
- use_case.extend (use_case.kind_of?(MatchWithArguments) ? MatchNumTimesWith : MatchNumTimes)
183
- use_case.expected_times_invoked = number
184
- end
205
+ matcher.failure_message_for_should { use_case.failure_message_for_should }
206
+ matcher.failure_message_for_should_not { use_case.failure_message_for_should_not }
207
+ end
185
208
 
186
- chain :with do |*arguments|
187
- use_case.extend (use_case.kind_of?(MatchNumTimes) ? MatchNumTimesWith : MatchWithArguments)
188
- use_case.expected_arguments = arguments
189
- end
190
209
 
191
- failure_message_for_should { use_case.failure_message_for_should }
192
- failure_message_for_should_not { use_case.failure_message_for_should_not }
210
+ # have_been_told_to
211
+ ::RSpec::Matchers.define :have_been_told_to do |verb|
212
+ surrogate_matcher[Handler.new(verb, :verb), self, true]
193
213
  end
194
214
 
195
215
 
196
216
  # have_been_asked_for_its
197
217
  ::RSpec::Matchers.define :have_been_asked_for_its do |noun|
198
- use_case = Handler.new noun, :noun
199
-
200
- match do |mocked_instance|
201
- use_case.instance = mocked_instance
202
- use_case.match?
203
- end
204
-
205
- chain :times do |number|
206
- use_case.extend (use_case.kind_of?(MatchWithArguments) ? MatchNumTimesWith : MatchNumTimes)
207
- use_case.expected_times_invoked = number
208
- end
209
-
210
- chain :with do |*arguments|
211
- use_case.extend (use_case.kind_of?(MatchNumTimes) ? MatchNumTimesWith : MatchWithArguments)
212
- use_case.expected_arguments = arguments
213
- end
214
-
215
- failure_message_for_should { use_case.failure_message_for_should }
216
- failure_message_for_should_not { use_case.failure_message_for_should_not }
218
+ surrogate_matcher[Handler.new(noun, :noun), self, true]
217
219
  end
218
220
 
219
221
 
220
222
  # have_been_initialized_with
221
223
  ::RSpec::Matchers.define :have_been_initialized_with do |*init_args|
222
- use_case = Handler.new :initialize, :verb
223
- use_case.extend MatchWithArguments
224
- use_case.expected_arguments = init_args
225
-
226
- match do |mocked_instance|
227
- use_case.instance = mocked_instance
228
- use_case.match?
229
- end
230
-
231
- failure_message_for_should do
232
- use_case.failure_message_for_should
233
- end
234
-
235
- failure_message_for_should_not do
236
- use_case.failure_message_for_should_not
237
- end
224
+ surrogate_matcher[Handler.new(:initialize, :verb).with(*init_args), self]
238
225
  end
239
226
  end
240
227
  end
@@ -1,4 +1,25 @@
1
1
  # Maybe I should be my own gem?
2
+
3
+ class Surrogate
4
+ module RSpec
5
+ class << self
6
+ def rspec_mocks_loaded?
7
+ return @mocks_loaded if @alrady_checked_mocks
8
+ @alrady_checked_mocks = true
9
+ require 'rspec/mocks' # can't figure out a way to do this lazily
10
+ @mocks_loaded = true
11
+ rescue LoadError
12
+ @mocks_loaded = false
13
+ end
14
+
15
+ def rspec_mocks_loaded=(bool)
16
+ @alrady_checked_mocks = true
17
+ @mocks_loaded = bool
18
+ end
19
+ end
20
+ end
21
+ end
22
+
2
23
  require 'surrogate'
3
24
  require 'surrogate/rspec/api_method_matchers'
4
25
  require 'surrogate/rspec/substitutability_matchers'
@@ -7,8 +7,13 @@ class Surrogate
7
7
  # convert raw arguments into a value
8
8
  def self.factory(*args, &block)
9
9
  arg = args.first
10
+ # if arg.kind_of? Exception
11
+ # Raiseable.new arg
12
+ # else
13
+ # MethodQueue.new args
14
+ # end
10
15
  if args.size > 1
11
- MethodQueue.new args
16
+ ValueQueue.new args
12
17
  elsif arg.kind_of? Exception
13
18
  Raisable.new arg
14
19
  elsif arg.kind_of? Value
@@ -45,7 +50,7 @@ class Surrogate
45
50
  end
46
51
 
47
52
 
48
- class MethodQueue < Value
53
+ class ValueQueue < Value
49
54
  QueueEmpty = Class.new StandardError
50
55
 
51
56
  def value(hatchling, method_name)
@@ -1,3 +1,3 @@
1
1
  class Surrogate
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -1,6 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'define' do
4
+ let(:mocked_class) { Surrogate.endow Class.new }
5
+ let(:instance) { mocked_class.new }
6
+
4
7
  describe 'in the block' do
5
8
  it 'is an api method for the class' do
6
9
  pristine_klass = Class.new do
@@ -18,248 +21,253 @@ describe 'define' do
18
21
 
19
22
 
20
23
  describe 'out of the block' do
21
- let(:mocked_class) { Surrogate.endow Class.new }
22
- let(:instance) { mocked_class.new }
23
-
24
24
  it 'is an api method for the instance' do
25
25
  mocked_class.define(:book) { 'book' }
26
26
  instance.book.should == 'book'
27
27
  end
28
+ end
28
29
 
29
- describe 'declaring the behaviour' do
30
- describe 'for verbs' do
31
- before { mocked_class.define :wink }
32
-
33
- describe 'will_<api_method>' do
34
- it 'overrides the default value for the api method' do
35
- mock1 = mocked_class.new
36
- mock2 = mocked_class.new
37
- mock1.will_wink :quickly
38
- mock2.will_wink :slowly
39
- mock1.wink.should == :quickly
40
- mock2.wink.should == :slowly
41
- mock1.wink.should == :quickly
42
- end
30
+ describe 'declaring the behaviour' do
43
31
 
44
- it 'returns the object' do
45
- instance = mocked_class.new
46
- instance.will_wink(:quickly).should equal instance
47
- end
32
+ describe 'for verbs' do
33
+ before { mocked_class.define :wink }
34
+
35
+ describe 'will_<api_method>' do
36
+ it 'overrides the default value for the api method' do
37
+ mock1 = mocked_class.new
38
+ mock2 = mocked_class.new
39
+ mock1.will_wink :quickly
40
+ mock2.will_wink :slowly
41
+ mock1.wink.should == :quickly
42
+ mock2.wink.should == :slowly
43
+ mock1.wink.should == :quickly
48
44
  end
49
45
 
50
- describe 'will_<api_method> with multiple arguments' do
51
- it 'returns the object' do
52
- instance = mocked_class.new
53
- instance.will_wink(1, 2, 3).should equal instance
54
- end
46
+ it 'returns the object' do
47
+ instance = mocked_class.new
48
+ instance.will_wink(:quickly).should equal instance
49
+ end
50
+ end
55
51
 
56
- context 'it creates a queue of things to find then returns to normal behaviour' do
57
- specify 'when there is no default block' do
58
- mock = mocked_class.new
59
- mock.will_wink :quickly, :slowly
60
- mock.wink.should == :quickly
61
- mock.wink.should == :slowly
62
- expect { mock.wink }.to raise_error Surrogate::UnpreparedMethodError
63
- end
52
+ describe 'will_<api_method> with multiple arguments' do
53
+ it 'returns the object' do
54
+ instance = mocked_class.new
55
+ instance.will_wink(1, 2, 3).should equal instance
56
+ end
64
57
 
65
- specify 'when there is a default block' do
66
- mocked_class = Surrogate.endow(Class.new)
67
- mocked_class.define(:connect) { :default }
68
- mock = mocked_class.new
69
- mock.will_connect 1, 2
70
- mock.connect.should == 1
71
- mock.connect.should == 2
72
- mock.connect.should == :default
73
- end
58
+ context 'it creates a queue of things to find then returns to normal behaviour' do
59
+ specify 'when there is no default block' do
60
+ mock = mocked_class.new
61
+ mock.will_wink :quickly, [:slowly]
62
+ mock.wink.should == :quickly
63
+ mock.wink.should == [:slowly]
64
+ expect { mock.wink }.to raise_error Surrogate::UnpreparedMethodError
74
65
  end
75
- end
76
66
 
77
- describe 'when an argument is an error' do
78
- it 'raises the error on method invocation' do
67
+ specify 'when there is a default block' do
79
68
  mocked_class = Surrogate.endow(Class.new)
80
- mocked_class.define :connect
69
+ mocked_class.define(:connect) { :default }
81
70
  mock = mocked_class.new
82
- error = StandardError.new("some message")
83
-
84
- # for single invocation
85
- mock.will_connect error
86
- expect { mock.connect }.to raise_error StandardError, "some message"
87
-
88
- # for queue
89
- mock.will_connect 1, error, 2
71
+ mock.will_connect 1, 2
90
72
  mock.connect.should == 1
91
- expect { mock.connect }.to raise_error StandardError, "some message"
92
73
  mock.connect.should == 2
74
+ mock.connect.should == :default
93
75
  end
94
76
  end
95
77
  end
96
78
 
79
+ describe 'when an argument is an error' do
80
+ it 'raises the error on method invocation' do
81
+ mocked_class = Surrogate.endow(Class.new)
82
+ mocked_class.define :connect
83
+ mock = mocked_class.new
84
+ error = StandardError.new("some message")
85
+
86
+ # for single invocation
87
+ mock.will_connect error
88
+ expect { mock.connect }.to raise_error StandardError, "some message"
89
+
90
+ # for queue
91
+ mock.will_connect 1, error, 2
92
+ mock.connect.should == 1
93
+ expect { mock.connect }.to raise_error StandardError, "some message"
94
+ mock.connect.should == 2
95
+ end
96
+ end
97
+ end
97
98
 
98
- describe 'for nouns' do
99
- before { mocked_class.define :age }
100
99
 
101
- describe 'will_have_<api_method>' do
102
- it 'defines will_have_<api_method> which overrides the default block' do
103
- mock1 = mocked_class.new
104
- mock2 = mocked_class.new
105
- mock1.will_have_age 12
106
- mock2.will_have_age 34
107
- mock1.age.should == 12
108
- mock2.age.should == 34
109
- mock1.age.should == 12
110
- end
100
+ describe 'for nouns' do
101
+ before { mocked_class.define :age }
111
102
 
112
- it 'returns the object' do
113
- instance = mocked_class.new
114
- instance.will_have_age(123).should equal instance
115
- end
103
+ describe 'will_have_<api_method>' do
104
+ it 'defines will_have_<api_method> which overrides the default block' do
105
+ mock1 = mocked_class.new
106
+ mock2 = mocked_class.new
107
+ mock1.will_have_age 12
108
+ mock2.will_have_age 34
109
+ mock1.age.should == 12
110
+ mock2.age.should == 34
111
+ mock1.age.should == 12
116
112
  end
117
113
 
118
- describe 'wil_have_<api_method> with multiple arguments' do
119
- it 'returns the object' do
120
- instance = mocked_class.new
121
- instance.will_have_age(1,2,3).should equal instance
122
- end
114
+ it 'returns the object' do
115
+ instance = mocked_class.new
116
+ instance.will_have_age(123).should equal instance
117
+ end
118
+ end
123
119
 
124
- context 'it creates a queue of things to find then returns to normal behaviour' do
125
- specify 'when there is no default block' do
126
- mock = mocked_class.new
127
- mock.will_have_age 12, 34
128
- mock.age.should == 12
129
- mock.age.should == 34
130
- expect { mock.age }.to raise_error Surrogate::UnpreparedMethodError
131
- end
120
+ describe 'wil_have_<api_method> with multiple arguments' do
121
+ it 'returns the object' do
122
+ instance = mocked_class.new
123
+ instance.will_have_age(1,2,3).should equal instance
124
+ end
132
125
 
133
- specify 'when there is a default block' do
134
- mocked_class = Surrogate.endow(Class.new)
135
- mocked_class.define(:name) { 'default' }
136
- mock = mocked_class.new
137
- mock.will_have_name 'a', 'b'
138
- mock.name.should == 'a'
139
- mock.name.should == 'b'
140
- mock.name.should == 'default'
141
- end
126
+ context 'it creates a queue of things to find then returns to normal behaviour' do
127
+ specify 'when there is no default block' do
128
+ mock = mocked_class.new
129
+ mock.will_have_age 12, 34
130
+ mock.age.should == 12
131
+ mock.age.should == 34
132
+ expect { mock.age }.to raise_error Surrogate::UnpreparedMethodError
133
+ end
134
+
135
+ specify 'when there is a default block' do
136
+ mocked_class = Surrogate.endow(Class.new)
137
+ mocked_class.define(:name) { 'default' }
138
+ mock = mocked_class.new
139
+ mock.will_have_name 'a', 'b'
140
+ mock.name.should == 'a'
141
+ mock.name.should == 'b'
142
+ mock.name.should == 'default'
142
143
  end
143
144
  end
144
145
  end
145
146
  end
147
+ end
146
148
 
147
149
 
148
150
 
149
- context 'the api method' do
150
- it 'takes any number of arguments' do
151
- mocked_class.define(:meth) { 1 }
152
- mocked_class.new.meth.should == 1
153
- mocked_class.new.meth(1).should == 1
154
- mocked_class.new.meth(1, 2).should == 1
155
- end
151
+ context 'the api method' do
152
+ it 'takes any number of arguments' do
153
+ mocked_class.define(:meth) { 1 }
154
+ mocked_class.new.meth.should == 1
155
+ mocked_class.new.meth(1).should == 1
156
+ mocked_class.new.meth(1, 2).should == 1
157
+ end
156
158
 
157
- it 'raises an UnpreparedMethodError when it has no default block' do
158
- mocked_class.define :meth
159
- expect { mocked_class.new.meth }.to raise_error(Surrogate::UnpreparedMethodError, /meth/)
160
- end
159
+ it 'raises an UnpreparedMethodError when it has no default block' do
160
+ mocked_class.define :meth
161
+ expect { mocked_class.new.meth }.to raise_error(Surrogate::UnpreparedMethodError, /meth/)
162
+ end
161
163
 
162
- it 'considers ivars of the same name to be its default' do
163
- mocked_class.define :meth
164
- mocked = mocked_class.new
165
- mocked.instance_variable_set :@meth, 123
166
- mocked.meth.should == 123
167
- end
164
+ it 'considers ivars of the same name to be its default when it has no suffix' do
165
+ mocked_class.define :meth
166
+ mocked = mocked_class.new
167
+ mocked.instance_variable_set :@meth, 123
168
+ mocked.meth.should == 123
169
+ end
170
+
171
+ it 'considers ivars ending in _p to be its default when it ends in a question mark' do
172
+ mocked_class.define :meth?
173
+ mocked = mocked_class.new
174
+ mocked.instance_variable_set :@meth_p, 123
175
+ mocked.meth?.should == 123
176
+ end
177
+
178
+ it 'reverts to the default block if invoked and having no ivar' do
179
+ mocked_class.define(:meth) { 123 }
180
+ mocked = mocked_class.new
181
+ mocked.instance_variable_get(:@meth).should be_nil
182
+ mocked.meth.should == 123
183
+ end
168
184
 
169
- it 'reverts to the default block if invoked and having no ivar' do
170
- mocked_class.define(:meth) { 123 }
171
- mocked = mocked_class.new
172
- mocked.instance_variable_get(:@meth).should be_nil
173
- mocked.meth.should == 123
185
+ describe 'initialization' do
186
+ specify 'api methods can be an initialize method' do
187
+ mocked_class.define(:initialize) { @abc = 123 }
188
+ mocked_class.new.instance_variable_get(:@abc).should == 123
174
189
  end
175
190
 
176
- describe 'initialization' do
177
- specify 'api methods can be an initialize method' do
178
- mocked_class.define(:initialize) { @abc = 123 }
179
- mocked_class.new.instance_variable_get(:@abc).should == 123
180
- end
191
+ specify 'initialize exsits even if error is raised' do
192
+ mocked_class.define(:initialize) { raise "simulate runtime error" }
193
+ expect { mocked_class.new }.to raise_error(RuntimeError, /simulate/)
194
+ expect { mocked_class.new }.to raise_error(RuntimeError, /simulate/)
195
+ end
181
196
 
182
- specify 'initialize exsits even if error is raised' do
183
- mocked_class.define(:initialize) { raise "simulate runtime error" }
184
- expect { mocked_class.new }.to raise_error(RuntimeError, /simulate/)
185
- expect { mocked_class.new }.to raise_error(RuntimeError, /simulate/)
186
- end
197
+ specify 'receives args' do
198
+ mocked_class.define(:initialize) { |num1, num2| @num = num1 + num2 }
199
+ mocked_class.new(25, 75).instance_variable_get(:@num).should == 100
200
+ end
187
201
 
188
- specify 'receives args' do
189
- mocked_class.define(:initialize) { |num1, num2| @num = num1 + num2 }
190
- mocked_class.new(25, 75).instance_variable_get(:@num).should == 100
191
- end
202
+ specify 'even works with inheritance' do
203
+ superclass = Class.new
204
+ superclass.send(:define_method, :initialize) { @a = 1 }
205
+ subclass = Surrogate.endow Class.new superclass
206
+ subclass.define :abc
207
+ subclass.new.instance_variable_get(:@a).should == 1
208
+ end
192
209
 
193
- specify 'even works with inheritance' do
194
- superclass = Class.new
195
- superclass.send(:define_method, :initialize) { @a = 1 }
196
- subclass = Surrogate.endow Class.new superclass
197
- subclass.define :abc
198
- subclass.new.instance_variable_get(:@a).should == 1
210
+ context 'when not an api method' do
211
+ it 'respects arity (this is probably 1.9.3 only)' do
212
+ expect { mocked_class.new 1 }.to raise_error ArgumentError, 'wrong number of arguments(1 for 0)'
199
213
  end
200
214
 
201
- context 'when not an api method' do
202
- it 'respects arity (this is probably 1.9.3 only)' do
203
- expect { mocked_class.new 1 }.to raise_error ArgumentError, 'wrong number of arguments(1 for 0)'
204
- end
205
-
206
- describe 'invocations are recorded anyway' do
207
- specify 'even when initialize is defined after surrogate block' do
208
- klass = Class.new do
209
- Surrogate.endow self
210
- def initialize(a) @a = a end
211
- end
212
- klass.new(1).should have_been_initialized_with 1
213
- klass.new(1).instance_variable_get(:@a).should == 1
215
+ describe 'invocations are recorded anyway' do
216
+ specify 'even when initialize is defined after surrogate block' do
217
+ klass = Class.new do
218
+ Surrogate.endow self
219
+ def initialize(a) @a = a end
214
220
  end
221
+ klass.new(1).should have_been_initialized_with 1
222
+ klass.new(1).instance_variable_get(:@a).should == 1
223
+ end
215
224
 
216
- specify 'even when initialize is defined before surrogate block' do
217
- klass = Class.new do
218
- def initialize(a) @a = a end
219
- Surrogate.endow self
220
- end
221
- klass.new(1).should have_been_initialized_with 1
222
- klass.new(1).instance_variable_get(:@a).should == 1
225
+ specify 'even when initialize is defined before surrogate block' do
226
+ klass = Class.new do
227
+ def initialize(a) @a = a end
228
+ Surrogate.endow self
223
229
  end
230
+ klass.new(1).should have_been_initialized_with 1
231
+ klass.new(1).instance_variable_get(:@a).should == 1
224
232
  end
225
233
  end
226
234
  end
235
+ end
227
236
 
228
- describe 'it takes a block whos return value will be used as the default' do
229
- specify 'the block is instance evaled' do
230
- mocked_class.define(:meth) { self }
231
- instance = mocked_class.new
232
- instance.meth.should equal instance
233
- end
234
-
235
- specify 'arguments passed to the method will be passed to the block' do
236
- mocked_class.define(:meth) { |*args| args }
237
- instance = mocked_class.new
238
- instance.meth(1).should == [1]
239
- instance.meth(1, 2).should == [1, 2]
240
- end
237
+ describe 'it takes a block whos return value will be used as the default' do
238
+ specify 'the block is instance evaled' do
239
+ mocked_class.define(:meth) { self }
240
+ instance = mocked_class.new
241
+ instance.meth.should equal instance
241
242
  end
242
243
 
243
- it 'remembers what it was invoked with' do
244
- mocked_class.define(:meth) { nil }
245
- mock = mocked_class.new
246
- mock.meth 1
247
- mock.meth 1, 2
248
- mock.meth [1, 2]
249
- mock.invocations(:meth).should == [
250
- [1],
251
- [1, 2],
252
- [[1, 2]],
253
- ]
244
+ specify 'arguments passed to the method will be passed to the block' do
245
+ mocked_class.define(:meth) { |*args| args }
246
+ instance = mocked_class.new
247
+ instance.meth(1).should == [1]
248
+ instance.meth(1, 2).should == [1, 2]
254
249
  end
250
+ end
255
251
 
256
- it 'raises an error if asked about invocations for api methods it does not know' do
257
- mocked_class.define :meth1
258
- mocked_class.define :meth2
259
- mock = mocked_class.new
260
- expect { mock.invocations(:meth1) }.to_not raise_error
261
- expect { mock.invocations(:meth3) }.to raise_error Surrogate::UnknownMethod, /doesn't know "meth3", only knows "initialize", "meth1", "meth2"/
262
- end
252
+ it 'remembers what it was invoked with' do
253
+ mocked_class.define(:meth) { nil }
254
+ mock = mocked_class.new
255
+ mock.meth 1
256
+ mock.meth 1, 2
257
+ mock.meth [1, 2]
258
+ mock.invocations(:meth).should == [
259
+ [1],
260
+ [1, 2],
261
+ [[1, 2]],
262
+ ]
263
+ end
264
+
265
+ it 'raises an error if asked about invocations for api methods it does not know' do
266
+ mocked_class.define :meth1
267
+ mocked_class.define :meth2
268
+ mock = mocked_class.new
269
+ expect { mock.invocations(:meth1) }.to_not raise_error
270
+ expect { mock.invocations(:meth3) }.to raise_error Surrogate::UnknownMethod, /doesn't know "meth3", only knows "initialize", "meth1", "meth2"/
263
271
  end
264
272
  end
265
273
 
@@ -60,12 +60,17 @@ describe 'RSpec matchers', 'have_been_asked_for_its' do
60
60
  end
61
61
 
62
62
  describe 'integration with rspec argument_matchers' do
63
- it 'works with no_args' do
63
+ it 'works with rspec matchers' do
64
64
  instance.should_not have_been_asked_for_its(:size).with(no_args)
65
65
  instance.size(1)
66
66
  instance.should_not have_been_asked_for_its(:size).with(no_args)
67
67
  instance.size
68
68
  instance.should have_been_asked_for_its(:size).with(no_args)
69
+
70
+ instance.should_not have_been_asked_for_its(:size).with(hash_including all: true)
71
+ instance.size any: false, all: true
72
+ instance.should have_been_asked_for_its(:size).with(hash_including all: true)
73
+ instance.should_not have_been_asked_for_its(:size).with(hash_including all: false)
69
74
  end
70
75
  end
71
76
  end
@@ -11,8 +11,9 @@ describe messages_for, 'argument inspection' do
11
11
  messages_for.inspect_argument([/a/]).should == "[/a/]"
12
12
  end
13
13
 
14
- it 'inspects no_args matcher' do
15
- messages_for.inspect_argument(no_args).should == 'no_args'
14
+ it 'inspects rspec matchers' do
15
+ messages_for.inspect_argument(no_args).should == 'no args'
16
+ messages_for.inspect_argument(hash_including abc: 123).should == 'hash_including(:abc=>123)'
16
17
  end
17
18
  end
18
19
 
@@ -23,11 +24,11 @@ describe messages_for, 'argument inspection' do
23
24
  end
24
25
 
25
26
  it "joins arguments with commas" do
26
- messages_for.inspect_arguments(['x', no_args]).should == "`\"x\", no_args'"
27
+ messages_for.inspect_arguments(['x', no_args]).should == "`\"x\", no args'"
27
28
  end
28
29
 
29
30
  it 'returns no_args when the array is empty' do
30
- messages_for.inspect_arguments([]).should == "`no_args'"
31
+ messages_for.inspect_arguments([]).should == "`no args'"
31
32
  end
32
33
  end
33
34
  end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'integration with rspec-mocks' do
4
+
5
+ let(:mp3) { Surrogate.endow(Class.new).define(:play) { }.new }
6
+
7
+ it 'knows that rspec-mocks is loaded' do
8
+ Surrogate::RSpec.rspec_mocks_loaded?.should equal true
9
+ end
10
+
11
+ context 'when rspec-mocks is loaded' do
12
+ it 'uses their matchers' do
13
+ mp3.play "Emily Wells"
14
+ mp3.should have_been_told_to(:play).with(/emily/i)
15
+ mp3.should_not have_been_told_to(:play).with(/emily/)
16
+
17
+ mp3.play /regex/
18
+ mp3.should have_been_told_to(:play).with(/regex/)
19
+ mp3.should_not have_been_told_to(:play).with(/xeger/)
20
+ end
21
+ end
22
+
23
+ context 'when rspec-mocks is not loaded' do
24
+ it 'does straight #== comparisons on each argument' do
25
+ begin
26
+ Surrogate::RSpec.rspec_mocks_loaded = false
27
+
28
+ mp3.play "Emily Wells"
29
+ mp3.should_not have_been_told_to(:play).with(/emily/i)
30
+
31
+ mp3.play /regex/
32
+ mp3.should have_been_told_to(:play).with(/regex/)
33
+ mp3.should_not have_been_told_to(:play).with(/xeger/)
34
+ rescue Exception
35
+ Surrogate::RSpec.rspec_mocks_loaded = true
36
+ end
37
+ end
38
+ end
39
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: surrogate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-03 00:00:00.000000000 Z
12
+ date: 2012-05-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70198239716160 !ruby/object:Gem::Requirement
16
+ requirement: &70344532950860 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 2.8.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70198239716160
24
+ version_requirements: *70344532950860
25
25
  description: Framework to aid in handrolling mock/spy objects.
26
26
  email:
27
27
  - josh.cheek@gmail.com
@@ -51,6 +51,7 @@ files:
51
51
  - spec/rspec/have_been_initialized_with_spec.rb
52
52
  - spec/rspec/have_been_told_to_spec.rb
53
53
  - spec/rspec/messages_spec.rb
54
+ - spec/rspec/rspec_mocks_integration_spec.rb
54
55
  - spec/rspec/substitute_for_spec.rb
55
56
  - spec/spec_helper.rb
56
57
  - spec/unit/api_comparer_spec.rb
@@ -86,6 +87,7 @@ test_files:
86
87
  - spec/rspec/have_been_initialized_with_spec.rb
87
88
  - spec/rspec/have_been_told_to_spec.rb
88
89
  - spec/rspec/messages_spec.rb
90
+ - spec/rspec/rspec_mocks_integration_spec.rb
89
91
  - spec/rspec/substitute_for_spec.rb
90
92
  - spec/spec_helper.rb
91
93
  - spec/unit/api_comparer_spec.rb