crispy 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5a304875b84ee789d83ba6420f4b57a2cd769d3
4
- data.tar.gz: 50dddf1394a740c51c7a15dbfd5d4bd3227388b8
3
+ metadata.gz: 906a71958302bc1652930a6e9f1c5aa237eaa233
4
+ data.tar.gz: 27951041fba2e5b62fb3d78d3b26311455ac5863
5
5
  SHA512:
6
- metadata.gz: 469caadde79084134b26358634de2830d156233e938b4ad2c1a21dd6653d0bd50d019530e6c5ad80bcf9b5e59526b135572bc8939b5d160b2f4a3f10129d79d8
7
- data.tar.gz: 902018025f544c073758117e5072896cb7dbf5b6cbc2a41f52b6116036a485a24ff23090e36718d94fdabe0ca7b9a27c21fa18db2bf61be6e255247029c2c58d
6
+ metadata.gz: 569d2a0881f1f684974e70ed3e50c11d73038d1b07a29964521d6d50e6beaad11e3943e2b53455d9140707cc635f5b0e617fd4907608a919c59f990b833695c7
7
+ data.tar.gz: 4b8dee5f09c25f3494b22ce3cf9a2f511489fb8d1ef70d430abf8e6b9eae99ae1aadb0c2add730c6037bdc32cbf41032a09f19b42912eb247780d05a5e0ba334
data/.travis.yml CHANGED
@@ -4,8 +4,8 @@ install:
4
4
  - bundle
5
5
  rvm:
6
6
  - ruby-head
7
- - 2.2.0-preview1
8
- - 2.1.3
7
+ - 2.2.0
8
+ - 2.1.5
9
9
  - 2.0.0
10
10
  script:
11
11
  - CODECLIMATE_REPO_TOKEN=fe75ea4329c1e131ef79de66f8ba2f605fa2fd352bbbd61fed5024cb6eaaba73 bundle exec rubydoctest README.md
@@ -22,4 +22,3 @@ addons:
22
22
  matrix:
23
23
  allow_failures:
24
24
  - rvm: ruby-head
25
- - rvm: 2.2.0-preview1
data/ChangeLog.md CHANGED
@@ -1,3 +1,14 @@
1
+ # 0.3.0 (2014.12.31)
2
+
3
+ - New Feature: Add stub feature to `ClassSpy`. [#23](https://github.com/igrep/crispy/pull/23)
4
+ - New Feature: Now double is automatically spied without `spy_into`. [#21](https://github.com/igrep/crispy/pull/21)
5
+ - Fix Bug: now `spy_into` replaces all stubber's methods with given stub spec when reinitialize a spy.[0f91579decbe27e6b05bec4b779dd1c3ede24380](https://github.com/igrep/crispy/commit/0f91579decbe27e6b05bec4b779dd1c3ede24380)
6
+ - Fix Bug: reset spy log when `spy_into`-ing an already spied object. e.g. Class.[#20](https://github.com/igrep/crispy/pull/20)
7
+ - New Feature: `spied?`. [#18](https://github.com/igrep/crispy/pull/18)
8
+ - Refactor many internal classes and tests. [#21](https://github.com/igrep/crispy/pull/21) [#22](https://github.com/igrep/crispy/pull/22) [#23](https://github.com/igrep/crispy/pull/23) [#24](https://github.com/igrep/crispy/pull/24)
9
+ - Loose required minitest's version.
10
+ - Minor document enhancements.
11
+
1
12
  # 0.2.0 (2014.11.1)
2
13
 
3
14
  - New Feature: `stub_const`. [#11](https://github.com/igrep/crispy/pull/11)
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Yamamoto Yuji
1
+ Copyright (c) 2014 Yuji Yamamoto
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -9,7 +9,7 @@ Test Spy for Any Object in Ruby.
9
9
 
10
10
  ## Features
11
11
 
12
- - Test spy for any object by using `prepend` (Sorry, it runs by Ruby 2.0 or higher!)
12
+ - Test spy for **ANY** object by using `prepend` (Sorry, it runs by Ruby 2.0 or higher!)
13
13
  - Extremely flexible query for received messages with `received_messages` method.
14
14
  - By using Array and Enumerable's methods, you never have to remember the complex API and tons of the argument matchers in RSpec anymore!
15
15
  - Makes mocks obsolete so you don't have to be worried about where to put the expectations (i.e. *before or after the subject method*).
@@ -42,8 +42,9 @@ doctest_require: './test/doctest-fixtures/your_cool_class.rb'
42
42
  >> include Crispy # import spy, spy_into and any other functions from Crispy namespace.
43
43
 
44
44
  >> object = YourCoolClass.new
45
- >> spy = spy_into object
45
+ >> spy_into object # sneak into your object to spy.
46
46
 
47
+ # Use your object as usual.
47
48
  >> object.your_cool_method 1, 2, 3
48
49
  >> object.your_method_without_argument
49
50
  >> object.your_lovely_method 'great', 'arguments'
@@ -101,7 +102,7 @@ Each argument is compared by `==` method.
101
102
  #### Get more detailed log
102
103
 
103
104
  You can check arbitrary received methods with the familliar Array's (and of course including Enumerable's!) methods such as `any?`, `all`, `first`, `[]`, `index`.
104
- Because `spy(object).received_messages` returns an array of `CrispyReceivedMessage` instances.
105
+ Because `spy(object).received_messages` returns an array of `CrispyReceivedMessage` instances.
105
106
  **You don't have to remember the tons of matchers for received arguments any more!!**
106
107
 
107
108
  ```ruby
@@ -118,6 +119,31 @@ Because `spy(object).received_messages` returns an array of `CrispyReceivedMessa
118
119
  => true
119
120
  ```
120
121
 
122
+ ### Stub Methods of a Spy
123
+
124
+ ```ruby
125
+ >> spy(object).stub(:your_cool_method, 'Awesome!')
126
+ >> object.your_cool_method
127
+ => "Awesome!"
128
+
129
+ >> spy(object).stub(your_lovely_method: 'I love this method!', your_finalizer: 'Finalized!')
130
+ >> object.your_lovely_method
131
+ => "I love this method!"
132
+ >> object.your_finalizer
133
+ => "Finalized!"
134
+ ```
135
+
136
+ Of cource stubbed methods are spied as well.
137
+
138
+ ```ruby
139
+ >> spy(object).received? :your_cool_method
140
+ => true
141
+
142
+ # `spy(object)` keeps its spied log of a method even after stubbing the method.
143
+ >> spy(object).count_received :your_lovely_method
144
+ => 3
145
+ ```
146
+
121
147
  ### Spy on Instances of a Class
122
148
 
123
149
  ```ruby
@@ -161,7 +187,7 @@ In addition, you can check which instance calles a method as well as its argumen
161
187
  => true
162
188
  ```
163
189
 
164
- Note that `spy_of_instances` stops to spy after called methods with `with_receiver` (or `with_receiver?`) prefix.
190
+ Note that `spy_of_instances` stops spying after called methods with `with_receiver` (or `with_receiver?`) prefix.
165
191
  This is to prevent the spy from unexpectedly logging methods used to compare its receiver (such as `==`).
166
192
 
167
193
  ```ruby
@@ -175,35 +201,36 @@ This is to prevent the spy from unexpectedly logging methods used to compare its
175
201
  >> # Perhaps you don't want to log methods in test code.
176
202
  >> instance.some_method_for_testing
177
203
  >> spy_of_instances(YourCoolClass::Again).received? :some_method_for_testing
178
- >> false
204
+ => false
179
205
  ```
180
206
 
181
207
  If you want to restart spying, use `restart` method literally.
182
208
 
183
209
  ```ruby
184
- >> spy_into_instances(YourCoolClass::Again).restart
210
+ >> spy_of_instances(YourCoolClass::Again).restart
185
211
 
186
212
  >> instance.some_method_for_testing
187
213
  >> spy_of_instances(YourCoolClass::Again).received? :some_method_for_testing
188
- >> true
214
+ => true
189
215
  ```
190
216
 
191
- ### Stub Methods of a Spy
217
+ ### Stub Methods of Instances of a Class
192
218
 
193
219
  ```ruby
194
- >> spy(object).stub(:your_cool_method, 'Awesome!')
195
- >> object.your_cool_method
196
- => "Awesome!"
220
+ >> spy_of_instances(YourCoolClass).stub(your_lovely_method: 'Even more lovely!', your_cool_method: 'much cooler!')
197
221
 
198
- >> spy(object).stub(your_lovely_method: 'I love this method!', your_finalizer: 'Finalized!')
199
- >> object.your_lovely_method
200
- => "I love this method!"
201
- >> object.your_finalizer
202
- => "Finalized!"
222
+ >> instance1.your_lovely_method
223
+ => "Even more lovely!"
224
+ >> instance2.your_cool_method
225
+ => "much cooler!"
203
226
  ```
204
227
 
205
228
  ### Stub Methods of a Double
206
229
 
230
+ Double can call Spy's method directly.
231
+ You do NOT need to write code such as `spy(your_double).stub(...)`.
232
+ Just `your_double.stub(...)`.
233
+
207
234
  ```ruby
208
235
  >> your_awesome_double = double('your awesome double', nice!: '+1!', sexy?: true)
209
236
  >> your_awesome_double.nice!
@@ -216,6 +243,18 @@ If you want to restart spying, use `restart` method literally.
216
243
  => "can be stubbed."
217
244
  ```
218
245
 
246
+ ### Spy on a Double
247
+
248
+ A double is spied without `spy_into`-ing.
249
+ And as `double.stub(...)`, Double can also call Spy's method such as `received?`
250
+
251
+ ```ruby
252
+ >> your_awesome_double.received? :nice!
253
+ => true
254
+ >> your_awesome_double.count_received :another_method
255
+ => 1
256
+ ```
257
+
219
258
  ### Stub Constants
220
259
 
221
260
  Specify the **fully qualified name of the constant** instead of the constant itself.
data/crispy.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.7"
24
24
  spec.add_development_dependency "rake"
25
- spec.add_development_dependency "minitest", "~> 5.4"
25
+ spec.add_development_dependency "minitest", "~> 5"
26
26
  spec.add_development_dependency "pry"
27
27
  spec.add_development_dependency "byebug"
28
28
  spec.add_development_dependency "rubydoctest"
@@ -1,29 +1,26 @@
1
1
  require 'crispy/crispy_received_message_with_receiver'
2
- require 'crispy/crispy_internal/spy_mixin'
3
- require 'crispy/crispy_internal/with_stubber'
2
+ require 'crispy/crispy_internal/spy_base'
4
3
 
5
4
  module Crispy
6
5
  module CrispyInternal
7
- class ClassSpy < ::Module
8
- include SpyMixin
9
- #include WithStubber
6
+ class ClassSpy < SpyBase
10
7
 
11
8
  @registry = {}
12
9
 
13
- def initialize klass#, stubs_map = {}
14
- spy = self
15
- super() do
16
- define_method(:__CRISPY_CLASS_SPY__) { spy }
17
- end
18
-
10
+ def initialize klass, stubs_map = {}
19
11
  @received_messages_with_receiver = []
20
- initialize_spy
21
12
 
22
- #initialize_stubber stubs_map
23
- #prepend_stubber klass
13
+ super
24
14
 
25
- prepend_features klass
26
- self.class.register spy: spy, of_class: klass
15
+ self.class.register spy: self, of_class: klass
16
+ end
17
+
18
+ def self.of_target klass
19
+ @registry[klass]
20
+ end
21
+
22
+ def target_to_class target_class
23
+ target_class
27
24
  end
28
25
 
29
26
  def received_messages
@@ -63,42 +60,16 @@ module Crispy
63
60
  @received_messages_with_receiver.clear
64
61
  end
65
62
 
66
- def append_received_message_with_receiver receiver, method_name, *arguments, &attached_block
67
- if @spying
68
- @received_messages_with_receiver <<
69
- ::Crispy::CrispyReceivedMessageWithReceiver.new(receiver, method_name, *arguments, &attached_block)
70
- end
71
- end
72
-
73
- def define_wrapper method_name
74
- define_method method_name do|*arguments, &attached_block|
75
- __CRISPY_CLASS_SPY__.append_received_message_with_receiver self, method_name, *arguments, &attached_block
76
-
77
- super(*arguments, &attached_block)
78
- end
79
- method_name
80
- end
81
- private :define_wrapper
82
-
83
- def self.new klass#, stubs_map = {}
84
- spy = self.of_class(klass)
85
- if spy
86
- spy.restart
87
- spy.erase_log
88
- spy
89
- else
90
- super
91
- end
63
+ def append_received_message receiver, method_name, *arguments, &attached_block
64
+ @received_messages_with_receiver <<
65
+ ::Crispy::CrispyReceivedMessageWithReceiver.new(receiver, method_name, *arguments, &attached_block)
92
66
  end
67
+ private :append_received_message
93
68
 
94
69
  def self.register(spy: nil, of_class: nil)
95
70
  @registry[of_class] = spy
96
71
  end
97
72
 
98
- def self.of_class(klass)
99
- @registry[klass]
100
- end
101
-
102
73
  end
103
74
  end
104
75
  end
@@ -1,23 +1,31 @@
1
- require 'crispy/crispy_internal/with_stubber'
2
-
3
1
  module Crispy
4
2
  module CrispyInternal
5
3
  class Double
6
- include WithStubber
7
4
 
8
5
  def initialize name_or_stubs_map = nil, stubs_map = {}
9
6
  if name_or_stubs_map.is_a? ::Hash
10
7
  @name = ''.freeze
11
- initialize_stubber(name_or_stubs_map)
8
+ @spy = ::Crispy.spy_into(self, name_or_stubs_map)
12
9
  else
13
10
  @name = name_or_stubs_map
14
- initialize_stubber(stubs_map)
11
+ @spy = ::Crispy.spy_into(self, stubs_map)
15
12
  end
16
- singleton_class =
17
- class << self
18
- self
13
+ end
14
+
15
+ def stub *arguments, &definition
16
+ @spy.stub(*arguments, &definition)
17
+ end
18
+
19
+ def received_messages
20
+ @spy.received_messages
21
+ end
22
+
23
+ SpyBase::COMMON_RECEIVED_MESSAGE_METHODS_DEFINITION.each_key do|method_name|
24
+ binding.eval(<<-END, __FILE__, (__LINE__ + 1))
25
+ def #{method_name} received_method_name, *received_arguments, &received_block
26
+ @spy.#{method_name} received_method_name, *received_arguments, &received_block
19
27
  end
20
- prepend_stubber singleton_class
28
+ END
21
29
  end
22
30
 
23
31
  end
@@ -1,54 +1,41 @@
1
1
  require 'crispy/crispy_received_message'
2
- require 'crispy/crispy_internal/spy_mixin'
3
- require 'crispy/crispy_internal/with_stubber'
2
+ require 'crispy/crispy_internal/spy_base'
4
3
 
5
4
  module Crispy
6
5
  module CrispyInternal
7
- class Spy < ::Module
8
- include SpyMixin
9
- include WithStubber
6
+ class Spy < SpyBase
10
7
 
11
8
  attr_reader :received_messages
12
9
 
13
10
  def initialize target, stubs_map = {}
14
- super() do
15
- spy = self
11
+ spy = self
12
+ module_eval do
16
13
  define_method(:__CRISPY_SPY__) { spy }
17
14
  end
18
15
 
19
16
  @received_messages = []
20
- initialize_spy
21
-
22
- singleton_class =
23
- class << target
24
- self
25
- end
26
- initialize_stubber stubs_map
27
- prepend_stubber singleton_class
17
+ super
18
+ end
28
19
 
29
- prepend_features singleton_class
20
+ def target_to_class target
21
+ class << target
22
+ self
23
+ end
30
24
  end
31
25
 
32
26
  def erase_log
33
27
  @received_messages.clear
34
28
  end
35
29
 
36
- def append_received_message method_name, *arguments, &attached_block
37
- if @spying
38
- @received_messages <<
39
- ::Crispy::CrispyReceivedMessage.new(method_name, *arguments, &attached_block)
40
- end
30
+ def self.of_target target
31
+ (defined? target.__CRISPY_SPY__) && target.__CRISPY_SPY__
41
32
  end
42
33
 
43
- def define_wrapper method_name
44
- define_method method_name do|*arguments, &attached_block|
45
- __CRISPY_SPY__.append_received_message(method_name, *arguments, &attached_block)
46
-
47
- super(*arguments, &attached_block)
48
- end
49
- method_name
34
+ def append_received_message receiver, method_name, *arguments, &attached_block
35
+ @received_messages <<
36
+ ::Crispy::CrispyReceivedMessage.new(method_name, *arguments, &attached_block)
50
37
  end
51
- private :define_wrapper
38
+ private :append_received_message
52
39
 
53
40
  end
54
41
  end
@@ -0,0 +1,157 @@
1
+ require 'crispy/crispy_received_message'
2
+
3
+ module Crispy
4
+ module CrispyInternal
5
+ class SpyBase < ::Module
6
+
7
+ public :remove_method
8
+
9
+ BLACK_LISTED_METHODS = [
10
+ :__CRISPY_SPY__,
11
+ ]
12
+
13
+ def initialize target, stubs_map = {}
14
+ prepend_features target_to_class(target)
15
+
16
+ @stubbed_methods = []
17
+ stub stubs_map
18
+
19
+ @spying = true
20
+ end
21
+
22
+ def self.new target, stubs_map = {}
23
+ spy = self.of_target(target)
24
+ if spy
25
+ spy.restart
26
+ spy.erase_log
27
+ spy.reinitialize_stubber stubs_map
28
+ spy
29
+ else
30
+ super
31
+ end
32
+ end
33
+
34
+ def self.of_target target
35
+ raise NotImplementedError
36
+ end
37
+
38
+ def target_to_class target
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def received_messages
43
+ raise NotImplementedError
44
+ end
45
+
46
+ def erase_log
47
+ raise NotImplementedError
48
+ end
49
+
50
+ def append_received_message receiver, method_name, *arguments, &attached_block
51
+ raise NotImplementedError
52
+ end
53
+
54
+ def stop
55
+ @spying = false
56
+ end
57
+
58
+ def restart
59
+ @spying = true
60
+ end
61
+
62
+ def define_wrapper method_name
63
+ spy = self
64
+ define_method method_name do|*arguments, &attached_block|
65
+ spy.append_received_message_when_spying(self, method_name, *arguments, &attached_block)
66
+
67
+ super(*arguments, &attached_block)
68
+ end
69
+ method_name
70
+ end
71
+ private :define_wrapper
72
+
73
+ def append_received_message_when_spying receiver, method_name, *arguments, &attached_block
74
+ if @spying
75
+ append_received_message receiver, method_name, *arguments, &attached_block
76
+ end
77
+ end
78
+
79
+ COMMON_RECEIVED_MESSAGE_METHODS_DEFINITION = {
80
+ 'received?' => 'include? %s',
81
+ 'received_once?' => 'one? {|self_thing| self_thing == %s }',
82
+ 'count_received' => 'count %s',
83
+ }
84
+
85
+ COMMON_RECEIVED_MESSAGE_METHODS_DEFINITION.each do|method_name, core_definition|
86
+ binding.eval(<<-END, __FILE__, (__LINE__ + 1))
87
+ def #{method_name} received_method_name, *received_arguments, &received_block
88
+ assert_symbol! received_method_name
89
+ if received_arguments.empty? and received_block.nil?
90
+ received_messages.map(&:method_name).#{sprintf(core_definition, 'received_method_name')}
91
+ else
92
+ received_message = ::Crispy::CrispyReceivedMessage.new(
93
+ received_method_name, *received_arguments, &received_block
94
+ )
95
+ received_messages.#{sprintf(core_definition, 'received_message')}
96
+ end
97
+ end
98
+ END
99
+ end
100
+
101
+ def stub method_name_or_hash, returned_value = nil, &definition
102
+ case method_name_or_hash
103
+ when Hash
104
+ hash = method_name_or_hash
105
+ hash.each do|method_name, value|
106
+ stub method_name, value
107
+ end
108
+ when ::Symbol, ::String
109
+ @stubbed_methods << method_name_or_hash
110
+
111
+ self.module_exec method_name_or_hash do|method_name|
112
+ spy = self
113
+
114
+ # remove methods already defined (maybe by define_wrapper) to avoid warning.
115
+ remove_method method_name if public_method_defined? method_name
116
+
117
+ # TODO: should not ignore arguments?
118
+ define_method(method_name) do|*arguments, &block|
119
+ spy.append_received_message_when_spying self, method_name, *arguments, &block
120
+ returned_value
121
+ end
122
+ end
123
+ end
124
+ self
125
+ end
126
+
127
+ def reinitialize_stubber stubs_map = {}
128
+ remove_method(*@stubbed_methods)
129
+ @stubbed_methods.clear
130
+ stub stubs_map
131
+ end
132
+
133
+ def prepend_features klass
134
+ super
135
+
136
+ klass.public_instance_methods.each do|method_name|
137
+ next if method_name == :__CRISPY_SPY__
138
+ self.module_eval { define_wrapper(method_name) }
139
+ end
140
+ klass.protected_instance_methods.each do|method_name|
141
+ self.module_eval { protected define_wrapper(method_name) }
142
+ end
143
+ klass.private_instance_methods.each do|method_name|
144
+ self.module_eval { private define_wrapper(method_name) }
145
+ end
146
+ end
147
+ private :prepend_features
148
+
149
+ def assert_symbol! maybe_symbol
150
+ unless maybe_symbol.respond_to?(:to_sym) && maybe_symbol.to_sym.instance_of?(::Symbol)
151
+ raise TypeError, "TypeError: no implicit conversion from #{maybe_symbol.inspect} to symbol"
152
+ end
153
+ end
154
+
155
+ end
156
+ end
157
+ end
@@ -17,14 +17,14 @@ module Crispy
17
17
 
18
18
  def == other
19
19
  @method_name == other.method_name &&
20
- @arguments == other.arguments &&
21
- @attached_block == other.attached_block
20
+ @arguments == other.arguments # &&
21
+ # @attached_block == other.attached_block
22
22
  end
23
23
 
24
24
  CLASS_NAME = self.name
25
25
 
26
26
  def to_s
27
- "#<#{CLASS_NAME}[#{(@method_name).inspect}, *#{@arguments.inspect}]>"
27
+ "#<#{CLASS_NAME}[#{@method_name.inspect}, *#{@arguments.inspect}]>"
28
28
  end
29
29
 
30
30
  alias inspect to_s
@@ -1,3 +1,3 @@
1
1
  module Crispy
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/crispy.rb CHANGED
@@ -18,8 +18,8 @@ module Crispy
18
18
  end
19
19
 
20
20
  # Make and returns a Crispy::ClassSpy's instance to spy all instances of a class.
21
- def spy_into_instances klass#, stubs_map = {}
22
- ::Crispy::CrispyInternal::ClassSpy.new klass
21
+ def spy_into_instances klass, stubs_map = {}
22
+ ::Crispy::CrispyInternal::ClassSpy.new klass, stubs_map
23
23
  end
24
24
 
25
25
  def spy object
@@ -27,7 +27,7 @@ module Crispy
27
27
  end
28
28
 
29
29
  def spy_of_instances klass
30
- ::Crispy::CrispyInternal::ClassSpy.of_class(klass)
30
+ ::Crispy::CrispyInternal::ClassSpy.of_target(klass)
31
31
  end
32
32
 
33
33
  def stub_const full_const_name, value
@@ -35,4 +35,8 @@ module Crispy
35
35
  ::Crispy::CrispyInternal::ConstChanger.save full_const_name, saved_value
36
36
  end
37
37
 
38
+ def spied? object
39
+ defined? object.__CRISPY_SPY__
40
+ end
41
+
38
42
  end
data/test/test_crispy.rb CHANGED
@@ -7,6 +7,20 @@ require 'minitest/autorun'
7
7
  class TestCrispy < MiniTest::Test
8
8
  include ::Crispy
9
9
 
10
+ module CommonSpyTests
11
+
12
+ def test_spy_is_also_returned_by_spy_into_method
13
+ assert_same @subject, @returned_spy
14
+ end
15
+
16
+ def test_spy_raises_error_given_non_symbol_as_method_name
17
+ assert_raises(::TypeError){ @subject.received?(nil) }
18
+ assert_raises(::TypeError){ @subject.received_once?(nil) }
19
+ assert_raises(::TypeError){ @subject.count_received(nil) }
20
+ end
21
+
22
+ end
23
+
10
24
  # Inherit BasicObject because it has fewer meta-programming methods than Object
11
25
  class ObjectClass < BasicObject
12
26
 
@@ -25,10 +39,13 @@ class TestCrispy < MiniTest::Test
25
39
  def baz
26
40
  end
27
41
  def method_to_stub1
28
- fail "Not stubbed actually! The test fails."
42
+ 'method to stub 1 (before stubbed)'
29
43
  end
30
44
  def method_to_stub2
31
- fail "Not stubbed actually! The test fails."
45
+ 'method to stub 2 (before stubbed)'
46
+ end
47
+ def method_to_stub3
48
+ 'method to stub 3 (before stubbed)'
32
49
  end
33
50
 
34
51
  def private_foo a
@@ -36,6 +53,43 @@ class TestCrispy < MiniTest::Test
36
53
  end
37
54
  private :private_foo
38
55
 
56
+ def self.hoge a, b, c
57
+ private_foo a
58
+ [a, b, c]
59
+ end
60
+ def self.foo
61
+ 123
62
+ end
63
+
64
+ def self.stubbed_method1
65
+ 'before stubbed 1'
66
+ end
67
+ def self.stubbed_method2
68
+ 'before stubbed 2'
69
+ end
70
+ def self.stubbed_method3
71
+ 'before stubbed 3'
72
+ end
73
+
74
+ def self.private_foo a
75
+ :private_foo
76
+ end
77
+ private_class_method :private_foo
78
+
79
+ end
80
+
81
+ class TestCrispySpied < TestCrispy
82
+
83
+ def test_spied_object_is_spied
84
+ spied_object = Object.new
85
+ spy_into spied_object
86
+ assert spied?(spied_object)
87
+ end
88
+
89
+ def test_non_spied_object_is_not_spied
90
+ assert not(spied?(Object.new))
91
+ end
92
+
39
93
  end
40
94
 
41
95
  class TestCrispyStubConst < TestCrispy
@@ -58,6 +112,7 @@ class TestCrispy < MiniTest::Test
58
112
  end
59
113
 
60
114
  class TestCrispySpyInto < TestCrispy
115
+ include CommonSpyTests
61
116
 
62
117
  def setup
63
118
  @object = ObjectClass.new
@@ -134,14 +189,41 @@ class TestCrispy < MiniTest::Test
134
189
  assert_equal(:stubbed2, @object.method_to_stub2)
135
190
  end
136
191
 
137
- def test_spy_is_also_returned_by_spy_into_method
138
- assert_same @subject, @returned_spy
192
+ end
193
+
194
+ class TestCrispySpyIntoClass < TestCrispy
195
+
196
+ def setup
197
+ spy_into ObjectClass, stubbed_method1: 1, stubbed_method2: 2
198
+
199
+ ObjectClass.hoge 1, 2, 3
200
+ ObjectClass.foo
201
+ ObjectClass.hoge 3, 4, 5
202
+
203
+ @subject = spy(ObjectClass)
139
204
  end
140
205
 
141
- def test_spy_raises_error_given_non_symbol_as_method_name
142
- assert_raises(::TypeError){ @subject.received_once?(nil) }
143
- assert_raises(::TypeError){ @subject.received_once?(nil) }
144
- assert_raises(::TypeError){ @subject.count_received(nil) }
206
+ def test_spy_logs_received_messages_not_twice_by_spy_into_twice
207
+ setup
208
+
209
+ assert_equal(
210
+ [
211
+ CrispyReceivedMessage[:hoge, 1, 2, 3],
212
+ CrispyReceivedMessage[:private_foo, 1],
213
+ CrispyReceivedMessage[:foo],
214
+ CrispyReceivedMessage[:hoge, 3, 4, 5],
215
+ CrispyReceivedMessage[:private_foo, 3],
216
+ ],
217
+ @subject.received_messages
218
+ )
219
+ end
220
+
221
+ def test_spy_overrides_stubbed_methods
222
+ spy_into ObjectClass, stubbed_method2: 'xx', stubbed_method3: 'xxx'
223
+
224
+ assert_equal 'before stubbed 1', ObjectClass.stubbed_method1
225
+ assert_equal 'xx' , ObjectClass.stubbed_method2
226
+ assert_equal 'xxx' , ObjectClass.stubbed_method3
145
227
  end
146
228
 
147
229
  end
@@ -154,7 +236,7 @@ class TestCrispy < MiniTest::Test
154
236
 
155
237
  def setup
156
238
  @returned_spy = spy_into_instances(
157
- object_class#, method_to_stub1: :stubbed_instance_method1, method_to_stub2: :stubbed_instance_method2
239
+ object_class, method_to_stub1: :stubbed_instance_method1, method_to_stub2: :stubbed_instance_method2
158
240
  )
159
241
 
160
242
  @subject = spy_of_instances(object_class)
@@ -173,7 +255,30 @@ class TestCrispy < MiniTest::Test
173
255
  CrispyWorld.reset
174
256
  end
175
257
 
258
+ module CommonClassSpyTests
259
+
260
+ def test_spy_changes_stubbed_method
261
+ @object_instances.each do|object|
262
+ assert_equal(:stubbed_instance_method1, object.method_to_stub1)
263
+ assert_equal(:stubbed_instance_method2, object.method_to_stub2)
264
+ end
265
+ end
266
+
267
+ def test_spy_overrides_stubbed_methods
268
+ spy_into_instances object_class, method_to_stub2: 'xx', method_to_stub3: 'xxx'
269
+
270
+ @object_instances.each do|object|
271
+ assert_equal 'method to stub 1 (before stubbed)', object.method_to_stub1
272
+ assert_equal 'xx' , object.method_to_stub2
273
+ assert_equal 'xxx' , object.method_to_stub3
274
+ end
275
+ end
276
+
277
+ end
278
+
176
279
  class TestReceivedMessage < self
280
+ include CommonSpyTests
281
+ include CommonClassSpyTests
177
282
 
178
283
  def object_class
179
284
  ObjectClass
@@ -246,15 +351,10 @@ class TestCrispy < MiniTest::Test
246
351
  assert_equal(2, @subject.count_received(:bar))
247
352
  end
248
353
 
249
- def test_spy_raises_error_given_non_symbol_as_method_name
250
- assert_raises(::TypeError){ @subject.received_once?(nil) }
251
- assert_raises(::TypeError){ @subject.received_once?(nil) }
252
- assert_raises(::TypeError){ @subject.count_received(nil) }
253
- end
254
-
255
354
  end
256
355
 
257
356
  class TestReceivedMessageWithReceiver < self
357
+ include CommonClassSpyTests
258
358
 
259
359
  def object_class
260
360
  ObjectClassNonBasic
@@ -275,10 +375,13 @@ class TestCrispy < MiniTest::Test
275
375
  def baz
276
376
  end
277
377
  def method_to_stub1
278
- fail "Not stubbed actually! The test fails."
378
+ 'method to stub 1 (before stubbed)'
279
379
  end
280
380
  def method_to_stub2
281
- fail "Not stubbed actually! The test fails."
381
+ 'method to stub 2 (before stubbed)'
382
+ end
383
+ def method_to_stub3
384
+ 'method to stub 3 (before stubbed)'
282
385
  end
283
386
 
284
387
  def private_foo a
@@ -436,9 +539,9 @@ class TestCrispy < MiniTest::Test
436
539
  end
437
540
 
438
541
  def test_spy_raises_error_given_non_symbol_as_method_name
439
- assert_raises(::TypeError){ @subject.received_once?(@object_instances[0], nil) }
440
- assert_raises(::TypeError){ @subject.received_once?(@object_instances[0], nil) }
441
- assert_raises(::TypeError){ @subject.count_received(@object_instances[0], nil) }
542
+ assert_raises(::TypeError){ @subject.received_with_receiver?(@object_instances[0], nil) }
543
+ assert_raises(::TypeError){ @subject.received_once_with_receiver?(@object_instances[0], nil) }
544
+ assert_raises(::TypeError){ @subject.count_received_with_receiver(@object_instances[0], nil) }
442
545
  end
443
546
 
444
547
  end
@@ -446,6 +549,7 @@ class TestCrispy < MiniTest::Test
446
549
  end
447
550
 
448
551
  class TestCrispyDouble < TestCrispy
552
+
449
553
  def setup
450
554
  @expected_hoge = Object.new
451
555
  @expected_foo = Object.new
@@ -472,6 +576,32 @@ class TestCrispy < MiniTest::Test
472
576
  assert_same @expected_baz, @actual_baz
473
577
  end
474
578
 
579
+ def test_double_can_be_spied
580
+ assert spied? @double
581
+
582
+ assert_same @double.received_messages, spy(@double).received_messages
583
+
584
+ assert @double.received?(:hoge)
585
+ assert @double.received_once?(:hoge, :with, :any, :arguments)
586
+ assert not(@double.received?(:hoge, 0, 0, 0))
587
+ assert not(@double.received_once?(:hoge, 0, 0, 0))
588
+ assert not(@double.received_once?(:hoge))
589
+ assert_equal 0, @double.count_received(:hoge, 0, 0, 0)
590
+ assert_equal 1, @double.count_received(:hoge, :with, :any, :arguments)
591
+ assert_equal 2, @double.count_received(:hoge)
592
+
593
+ assert @double.received?(:bar)
594
+ assert @double.received_once?(:bar)
595
+
596
+ assert @double.received_once?(:foo)
597
+ assert @double.received?(:foo)
598
+ assert_equal 1, @double.count_received(:foo)
599
+
600
+ assert not(@double.received?(:non_used_method))
601
+ assert not(@double.received_once?(:non_used_method))
602
+ assert_equal 0, @double.count_received(:non_used_method)
603
+ end
604
+
475
605
  end
476
606
 
477
607
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crispy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yamamoto Yuji
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-02 00:00:00.000000000 Z
11
+ date: 2014-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '5.4'
47
+ version: '5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '5.4'
54
+ version: '5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -116,9 +116,7 @@ files:
116
116
  - lib/crispy/crispy_internal/const_changer.rb
117
117
  - lib/crispy/crispy_internal/double.rb
118
118
  - lib/crispy/crispy_internal/spy.rb
119
- - lib/crispy/crispy_internal/spy_mixin.rb
120
- - lib/crispy/crispy_internal/stubber.rb
121
- - lib/crispy/crispy_internal/with_stubber.rb
119
+ - lib/crispy/crispy_internal/spy_base.rb
122
120
  - lib/crispy/crispy_received_message.rb
123
121
  - lib/crispy/crispy_received_message_with_receiver.rb
124
122
  - lib/crispy/crispy_world.rb
@@ -146,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
144
  version: '0'
147
145
  requirements: []
148
146
  rubyforge_project:
149
- rubygems_version: 2.2.2
147
+ rubygems_version: 2.4.5
150
148
  signing_key:
151
149
  specification_version: 4
152
150
  summary: Test spy for any object.
@@ -1,83 +0,0 @@
1
- require 'crispy/crispy_received_message'
2
-
3
- module Crispy
4
- module CrispyInternal
5
- module SpyMixin
6
-
7
- BLACK_LISTED_METHODS = [
8
- :__CRISPY_CLASS_SPY__,
9
- :__CRISPY_SPY__,
10
- ]
11
-
12
- def received_messages
13
- raise NotImplementedError
14
- end
15
-
16
- def erase_log
17
- raise NotImplementedError
18
- end
19
-
20
- def stop
21
- @spying = false
22
- end
23
-
24
- def restart
25
- @spying = true
26
- end
27
-
28
- COMMON_RECEIVED_MESSAGE_METHODS_DEFINITION = {
29
- 'received?' => 'include? %s',
30
- 'received_once?' => 'one? {|self_thing| self_thing == %s }',
31
- 'count_received' => 'count %s',
32
- }
33
-
34
- COMMON_RECEIVED_MESSAGE_METHODS_DEFINITION.each do|method_name, core_definition|
35
- binding.eval(<<-END, __FILE__, (__LINE__ + 1))
36
- def #{method_name} received_method_name, *received_arguments, &received_block
37
- assert_symbol! received_method_name
38
- if received_arguments.empty? and received_block.nil?
39
- received_messages.map(&:method_name).#{sprintf(core_definition, 'received_method_name')}
40
- else
41
- received_message = ::Crispy::CrispyReceivedMessage.new(
42
- received_method_name, *received_arguments, &received_block
43
- )
44
- received_messages.#{sprintf(core_definition, 'received_message')}
45
- end
46
- end
47
- END
48
- end
49
-
50
- def prepend_features klass
51
- super
52
-
53
- without_black_listed_methods(klass.public_instance_methods).each do|method_name|
54
- self.module_eval { define_wrapper(method_name) }
55
- end
56
- klass.protected_instance_methods.each do|method_name|
57
- self.module_eval { protected define_wrapper(method_name) }
58
- end
59
- klass.private_instance_methods.each do|method_name|
60
- self.module_eval { private define_wrapper(method_name) }
61
- end
62
- end
63
- private :prepend_features
64
-
65
- def without_black_listed_methods method_names
66
- method_names.reject {|method_name| BLACK_LISTED_METHODS.include? method_name }
67
- end
68
- private :without_black_listed_methods
69
-
70
- def initialize_spy
71
- @spying = true
72
- end
73
- private :initialize_spy
74
-
75
- def assert_symbol! maybe_symbol
76
- unless maybe_symbol.respond_to?(:to_sym) && maybe_symbol.to_sym.instance_of?(::Symbol)
77
- raise TypeError, "TypeError: no implicit conversion from #{maybe_symbol.inspect} to symbol"
78
- end
79
- end
80
-
81
- end
82
- end
83
- end
@@ -1,31 +0,0 @@
1
- module Crispy
2
- module CrispyInternal
3
- class Stubber < Module
4
- public :prepend_features
5
-
6
- def initialize stubs_map = {}
7
- super()
8
- stub stubs_map
9
- end
10
-
11
- NOT_SPECIFIED = ::Object.new
12
-
13
- def stub method_name_or_hash, returned_value = NOT_SPECIFIED, &definition
14
- case method_name_or_hash
15
- when Hash
16
- hash = method_name_or_hash
17
- hash.each do|method_name, value|
18
- stub method_name, value
19
- end
20
- when ::Symbol, ::String
21
- self.module_exec method_name_or_hash do|method_name|
22
- # TODO: should not ignore arguments?
23
- define_method(method_name) {|*_arguments| returned_value }
24
- end
25
- end
26
- self
27
- end
28
-
29
- end
30
- end
31
- end
@@ -1,24 +0,0 @@
1
- require 'crispy/crispy_internal/stubber'
2
-
3
- module Crispy
4
- module CrispyInternal
5
- module WithStubber
6
-
7
- def initialize_stubber stubs_map = {}
8
- @__CRISPY_STUBBER__ = Stubber.new(stubs_map)
9
- end
10
- private :initialize_stubber
11
-
12
- def prepend_stubber klass
13
- @__CRISPY_STUBBER__.prepend_features klass
14
- end
15
- private :prepend_stubber
16
-
17
- def stub *arguments, &definition
18
- @__CRISPY_STUBBER__.stub(*arguments, &definition)
19
- self
20
- end
21
-
22
- end
23
- end
24
- end