vcr 2.0.0.beta2 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +0 -2
  3. data/CHANGELOG.md +22 -1
  4. data/CONTRIBUTING.md +46 -0
  5. data/Gemfile +1 -9
  6. data/README.md +8 -2
  7. data/Rakefile +12 -1
  8. data/cucumber.yml +8 -9
  9. data/features/.nav +10 -4
  10. data/features/cassettes/format.feature +1 -1
  11. data/features/cassettes/no_cassette.feature +8 -11
  12. data/features/configuration/allow_http_connections_when_no_cassette.feature +4 -4
  13. data/features/configuration/filter_sensitive_data.feature +3 -0
  14. data/features/configuration/hook_into.feature +4 -8
  15. data/features/configuration/ignore_request.feature +191 -0
  16. data/features/getting_started.md +38 -21
  17. data/features/hooks/after_http_request.feature +44 -0
  18. data/features/hooks/around_http_request.feature +56 -0
  19. data/features/hooks/before_http_request.feature +44 -0
  20. data/features/hooks/before_playback.feature +181 -0
  21. data/features/hooks/before_record.feature +172 -0
  22. data/features/middleware/faraday.feature +7 -3
  23. data/features/record_modes/none.feature +2 -1
  24. data/features/record_modes/once.feature +2 -1
  25. data/features/request_matching/body.feature +2 -2
  26. data/features/request_matching/custom_matcher.feature +2 -2
  27. data/features/request_matching/headers.feature +2 -2
  28. data/features/request_matching/host.feature +2 -2
  29. data/features/request_matching/identical_request_sequence.feature +2 -2
  30. data/features/request_matching/method.feature +2 -2
  31. data/features/request_matching/path.feature +2 -2
  32. data/features/request_matching/playback_repeats.feature +2 -1
  33. data/features/request_matching/uri.feature +2 -2
  34. data/features/support/env.rb +21 -12
  35. data/features/test_frameworks/cucumber.feature +9 -4
  36. data/features/test_frameworks/{rspec.feature → rspec_macro.feature} +7 -7
  37. data/features/test_frameworks/rspec_metadata.feature +90 -0
  38. data/lib/vcr.rb +1 -1
  39. data/lib/vcr/cassette.rb +3 -3
  40. data/lib/vcr/cassette/http_interaction_list.rb +13 -9
  41. data/lib/vcr/cassette/migrator.rb +1 -1
  42. data/lib/vcr/configuration.rb +37 -0
  43. data/lib/vcr/errors.rb +172 -6
  44. data/lib/vcr/library_hooks.rb +4 -6
  45. data/lib/vcr/library_hooks/excon.rb +23 -11
  46. data/lib/vcr/library_hooks/fakeweb.rb +85 -24
  47. data/lib/vcr/library_hooks/faraday.rb +30 -2
  48. data/lib/vcr/library_hooks/typhoeus.rb +25 -3
  49. data/lib/vcr/library_hooks/webmock.rb +25 -36
  50. data/lib/vcr/middleware/faraday.rb +23 -5
  51. data/lib/vcr/request_handler.rb +12 -1
  52. data/lib/vcr/request_ignorer.rb +12 -1
  53. data/lib/vcr/request_matcher_registry.rb +1 -9
  54. data/lib/vcr/structs.rb +32 -2
  55. data/lib/vcr/test_frameworks/rspec.rb +28 -0
  56. data/lib/vcr/util/hooks.rb +12 -4
  57. data/lib/vcr/util/version_checker.rb +2 -0
  58. data/lib/vcr/version.rb +1 -1
  59. data/spec/fixtures/cassette_spec/example.yml +1 -1
  60. data/spec/fixtures/{fake_example.com_responses.yml → fake_example_responses.yml} +0 -0
  61. data/spec/monkey_patches.rb +1 -1
  62. data/spec/spec_helper.rb +3 -1
  63. data/spec/support/http_library_adapters.rb +4 -3
  64. data/spec/support/shared_example_groups/hook_into_http_library.rb +194 -12
  65. data/spec/support/shared_example_groups/request_hooks.rb +58 -0
  66. data/spec/support/shared_example_groups/version_checking.rb +5 -0
  67. data/spec/support/sinatra_app.rb +17 -9
  68. data/spec/support/vcr_stub_helpers.rb +17 -0
  69. data/spec/vcr/cassette/http_interaction_list_spec.rb +28 -29
  70. data/spec/vcr/cassette/migrator_spec.rb +6 -7
  71. data/spec/vcr/cassette_spec.rb +5 -5
  72. data/spec/vcr/configuration_spec.rb +51 -32
  73. data/spec/vcr/deprecations_spec.rb +0 -8
  74. data/spec/vcr/errors_spec.rb +129 -0
  75. data/spec/vcr/library_hooks/excon_spec.rb +21 -4
  76. data/spec/vcr/library_hooks/fakeweb_spec.rb +71 -3
  77. data/spec/vcr/library_hooks/faraday_spec.rb +45 -0
  78. data/spec/vcr/library_hooks/typhoeus_spec.rb +31 -1
  79. data/spec/vcr/library_hooks/webmock_spec.rb +26 -3
  80. data/spec/vcr/middleware/faraday_spec.rb +84 -1
  81. data/spec/vcr/request_ignorer_spec.rb +16 -0
  82. data/spec/vcr/request_matcher_registry_spec.rb +0 -26
  83. data/spec/vcr/structs_spec.rb +61 -1
  84. data/spec/vcr/test_frameworks/rspec_spec.rb +32 -0
  85. data/spec/vcr/util/hooks_spec.rb +73 -63
  86. data/spec/vcr_spec.rb +2 -2
  87. data/vcr.gemspec +5 -5
  88. metadata +51 -31
  89. data/features/configuration/hooks.feature +0 -270
  90. data/features/configuration/ignore_hosts.feature +0 -61
  91. data/features/configuration/ignore_localhost.feature +0 -97
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'vcr/library_hooks/faraday'
3
+
4
+ describe "Faraday hook" do
5
+ it 'inserts the VCR middleware just before the adapter' do
6
+ conn = Faraday.new(:url => 'http://sushi.com') do |builder|
7
+ builder.request :url_encoded
8
+ builder.request :json
9
+ builder.response :logger
10
+ builder.adapter :net_http
11
+ end
12
+
13
+ conn.builder.lock!
14
+ conn.builder.handlers.last(2).map(&:klass).should eq([
15
+ VCR::Middleware::Faraday,
16
+ Faraday::Adapter::NetHttp
17
+ ])
18
+ end
19
+
20
+ it 'handles the case where no adapter is declared' do
21
+ conn = Faraday.new
22
+
23
+ conn.builder.lock!
24
+ conn.builder.handlers.last(2).map(&:klass).should eq([
25
+ VCR::Middleware::Faraday,
26
+ Faraday::Adapter::NetHttp
27
+ ])
28
+ end
29
+
30
+ it 'does nothing if the VCR middleware has already been included' do
31
+ conn = Faraday.new(:url => 'http://sushi.com') do |builder|
32
+ builder.use VCR::Middleware::Faraday
33
+ builder.use Faraday::Response::Logger
34
+ builder.use Faraday::Adapter::NetHttp
35
+ end
36
+
37
+ conn.builder.lock!
38
+ conn.builder.handlers.map(&:klass).should eq([
39
+ VCR::Middleware::Faraday,
40
+ Faraday::Response::Logger,
41
+ Faraday::Adapter::NetHttp
42
+ ])
43
+ end
44
+ end
45
+
@@ -1,7 +1,35 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Typhoeus hook", :with_monkey_patches => :typhoeus do
4
- it_behaves_like 'a hook into an HTTP library', 'typhoeus'
4
+ after(:each) do
5
+ ::Typhoeus::Hydra.clear_stubs
6
+ end
7
+
8
+ def disable_real_connections
9
+ ::Typhoeus::Hydra.allow_net_connect = false
10
+ ::Typhoeus::Hydra::NetConnectNotAllowedError
11
+ end
12
+
13
+ def enable_real_connections
14
+ ::Typhoeus::Hydra.allow_net_connect = true
15
+ end
16
+
17
+ def directly_stub_request(method, url, response_body)
18
+ response = ::Typhoeus::Response.new(:code => 200, :body => response_body)
19
+ ::Typhoeus::Hydra.stub(method, url).and_return(response)
20
+ end
21
+
22
+ it_behaves_like 'a hook into an HTTP library', :typhoeus, 'typhoeus'
23
+
24
+ def stub_callback_registration
25
+ # stub the callback registration methods so we don't get a second
26
+ # callback registered when we load the typhoeus file below.
27
+ # Note that we have to use `stub!`, not `stub` because
28
+ # Typhoeus::Hydra defines its own stub method...so to use RSpec's,
29
+ # we use stub!
30
+ ::Typhoeus::Hydra.stub!(:after_request_before_on_complete)
31
+ ::Typhoeus::Hydra.stub!(:register_stub_finder)
32
+ end
5
33
 
6
34
  it_performs('version checking', 'Typhoeus',
7
35
  :valid => %w[ 0.3.2 0.3.10 ],
@@ -18,6 +46,8 @@ describe "Typhoeus hook", :with_monkey_patches => :typhoeus do
18
46
  end
19
47
 
20
48
  describe "VCR.configuration.after_library_hooks_loaded hook", :disable_warnings do
49
+ before(:each) { stub_callback_registration }
50
+
21
51
  it 'disables the webmock typhoeus adapter so it does not conflict with our typhoeus hook' do
22
52
  load "vcr/library_hooks/typhoeus.rb" # to re-add the hook since it's cleared by each test
23
53
  ::WebMock::HttpLibAdapters::TyphoeusAdapter.should_receive(:disable!)
@@ -1,8 +1,25 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "WebMock hook", :with_monkey_patches => :webmock do
4
+ after(:each) do
5
+ ::WebMock.reset!
6
+ end
7
+
8
+ def disable_real_connections
9
+ ::WebMock.disable_net_connect!
10
+ ::WebMock::NetConnectNotAllowedError
11
+ end
12
+
13
+ def enable_real_connections
14
+ ::WebMock.allow_net_connect!
15
+ end
16
+
17
+ def directly_stub_request(method, url, response_body)
18
+ ::WebMock.stub_request(method, url).to_return(:body => response_body)
19
+ end
20
+
4
21
  %w[net/http patron httpclient em-http-request curb typhoeus].each do |lib|
5
- it_behaves_like 'a hook into an HTTP library', lib do
22
+ it_behaves_like 'a hook into an HTTP library', :webmock, lib do
6
23
  if lib == 'net/http'
7
24
  def normalize_request_headers(headers)
8
25
  headers.merge(DEFAULT_REQUEST_HEADERS)
@@ -12,10 +29,16 @@ describe "WebMock hook", :with_monkey_patches => :webmock do
12
29
  end
13
30
 
14
31
  it_performs('version checking', 'WebMock',
15
- :valid => %w[ 1.7.0 1.7.99 ],
16
- :too_low => %w[ 0.9.9 0.9.10 0.1.30 1.0.30 1.6.9 ],
32
+ :valid => %w[ 1.7.8 1.7.10 1.7.99 ],
33
+ :too_low => %w[ 0.9.9 0.9.10 0.1.30 1.0.30 1.7.7 ],
17
34
  :too_high => %w[ 1.8.0 1.10.0 2.0.0 ]
18
35
  ) do
36
+
37
+ def stub_callback_registration
38
+ ::WebMock.stub(:after_request)
39
+ ::WebMock.stub(:globally_stub_request)
40
+ end
41
+
19
42
  def stub_version(version)
20
43
  WebMock.stub(:version).and_return(version)
21
44
  end
@@ -1,8 +1,9 @@
1
1
  require 'spec_helper'
2
+ require 'vcr/library_hooks/faraday'
2
3
 
3
4
  describe VCR::Middleware::Faraday do
4
5
  %w[ typhoeus net_http patron ].each do |lib|
5
- it_behaves_like 'a hook into an HTTP library', "faraday (w/ #{lib})",
6
+ it_behaves_like 'a hook into an HTTP library', :faraday, "faraday (w/ #{lib})",
6
7
  :status_message_not_exposed,
7
8
  :does_not_support_rotating_responses,
8
9
  :not_disableable
@@ -22,4 +23,86 @@ describe VCR::Middleware::Faraday do
22
23
  ::Faraday::VERSION = version
23
24
  end
24
25
  end
26
+
27
+ context 'when making parallel requests' do
28
+ include VCRStubHelpers
29
+ let(:parallel_manager) { ::Faraday::Adapter::Typhoeus.setup_parallel_manager }
30
+ let(:connection) { ::Faraday.new { |b| b.adapter :typhoeus } }
31
+
32
+ shared_examples_for "exclusive library hook" do
33
+ let(:request_url) { "http://localhost:#{VCR::SinatraApp.port}/" }
34
+
35
+ def make_request
36
+ connection.in_parallel(parallel_manager) { connection.get(request_url) }
37
+ end
38
+
39
+ it 'makes the faraday middleware exclusively enabled for the duration of the request' do
40
+ VCR.library_hooks.should_not be_disabled(:fakeweb)
41
+
42
+ hook_called = false
43
+ VCR.configuration.after_http_request do
44
+ hook_called = true
45
+ VCR.library_hooks.should be_disabled(:fakeweb)
46
+ end
47
+
48
+ make_request
49
+ VCR.library_hooks.should_not be_disabled(:fakeweb)
50
+ hook_called.should be_true
51
+ end
52
+ end
53
+
54
+ context 'for an ignored request' do
55
+ before(:each) { VCR.configuration.ignore_request { true } }
56
+ it_behaves_like "exclusive library hook"
57
+ end
58
+
59
+ context 'for a stubbed request' do
60
+ it_behaves_like "exclusive library hook" do
61
+ before(:each) do
62
+ stub_requests([http_interaction(request_url)], [:method, :uri])
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'for a recorded request' do
68
+ let!(:inserted_cassette) { VCR.insert_cassette('new_cassette') }
69
+ before(:each) { VCR.should_receive(:record_http_interaction) }
70
+ it_behaves_like "exclusive library hook"
71
+ end
72
+
73
+ context 'for a disallowed request' do
74
+ it_behaves_like "exclusive library hook" do
75
+ undef make_request
76
+ def make_request
77
+ expect {
78
+ connection.in_parallel(parallel_manager) { connection.get(request_url) }
79
+ }.to raise_error(VCR::Errors::UnhandledHTTPRequestError)
80
+ end
81
+ end
82
+ end
83
+
84
+ it_behaves_like "request hooks", :faraday do
85
+ let!(:inserted_cassette) { VCR.insert_cassette('new_cassette') }
86
+
87
+ undef make_request
88
+ def make_request(disabled = false)
89
+ response = nil
90
+ connection.in_parallel(parallel_manager) do
91
+ response = connection.get(request_url)
92
+ end
93
+ response
94
+ end
95
+
96
+ it 'can be used to eject a cassette after the request is recorded' do
97
+ VCR.configuration.after_http_request { |request| VCR.eject_cassette }
98
+
99
+ VCR.should_receive(:record_http_interaction) do |interaction|
100
+ VCR.current_cassette.should be(inserted_cassette)
101
+ end
102
+
103
+ make_request
104
+ VCR.current_cassette.should be_nil
105
+ end
106
+ end
107
+ end if defined?(::Typhoeus)
25
108
  end
@@ -49,6 +49,22 @@ module VCR
49
49
  it_behaves_like "#ignore?", "http://#{host}/foo", false
50
50
  end
51
51
  end
52
+
53
+ context 'when a custom ignore_request hook has been set' do
54
+ before(:each) do
55
+ subject.ignore_request do |request|
56
+ URI(request.uri).port == 5
57
+ end
58
+ end
59
+
60
+ it 'ignores requests for which the block returns true' do
61
+ subject.ignore?(request('http://foo.com:5/bar')).should be_true
62
+ end
63
+
64
+ it 'does not ignore requests for which the block returns false' do
65
+ subject.ignore?(request('http://foo.com:6/bar')).should be_false
66
+ end
67
+ end
52
68
  end
53
69
  end
54
70
 
@@ -168,32 +168,6 @@ module VCR
168
168
  request_with(:uri => 'http://foo2.com/bar?baz=7')
169
169
  ).should be_false
170
170
  end
171
-
172
- it 'does not consider the standard HTTP port' do
173
- subject[:uri].matches?(
174
- request_with(:uri => 'http://foo.com:80/bar?baz=7'),
175
- request_with(:uri => 'http://foo.com/bar?baz=7')
176
- ).should be_true
177
- end
178
-
179
- it 'does not consider the standard HTTPS port' do
180
- subject[:uri].matches?(
181
- request_with(:uri => 'https://foo.com/bar?baz=7'),
182
- request_with(:uri => 'https://foo.com:443/bar?baz=7')
183
- ).should be_true
184
- end
185
-
186
- it 'considers non-standard ports' do
187
- subject[:uri].matches?(
188
- request_with(:uri => 'http://foo.com:79/bar?baz=7'),
189
- request_with(:uri => 'http://foo.com:78/bar?baz=7')
190
- ).should be_false
191
-
192
- subject[:uri].matches?(
193
- request_with(:uri => 'https://foo.com:442/bar?baz=7'),
194
- request_with(:uri => 'https://foo.com:441/bar?baz=7')
195
- ).should be_false
196
- end
197
171
  end
198
172
 
199
173
  describe ":host" do
@@ -1,3 +1,5 @@
1
+ # encoding: UTF-8
2
+
1
3
  require 'yaml'
2
4
  require 'vcr/structs'
3
5
 
@@ -222,7 +224,7 @@ module VCR
222
224
  end
223
225
 
224
226
  it 'replaces sensitive text in the request URI' do
225
- subject.request.uri.should eq('http://example-AAA.com:80/AAA/')
227
+ subject.request.uri.should eq('http://example-AAA.com/AAA/')
226
228
  end
227
229
  end
228
230
  end
@@ -244,8 +246,59 @@ module VCR
244
246
  m.call.should eq(described_class)
245
247
  end
246
248
  end
249
+
250
+ it 'gets normalized to a lowercase symbol' do
251
+ VCR::Request.new("GET").method.should eq(:get)
252
+ VCR::Request.new(:GET).method.should eq(:get)
253
+ VCR::Request.new(:get).method.should eq(:get)
254
+ VCR::Request.new("get").method.should eq(:get)
255
+ end
256
+ end
257
+
258
+ describe "#uri" do
259
+ def uri_for(uri)
260
+ VCR::Request.new(:get, uri).uri
261
+ end
262
+
263
+ it 'removes the default http port' do
264
+ uri_for("http://foo.com:80/bar").should eq("http://foo.com/bar")
265
+ end
266
+
267
+ it 'removes the default https port' do
268
+ uri_for("https://foo.com:443/bar").should eq("https://foo.com/bar")
269
+ end
270
+
271
+ it 'does not remove a non-standard http port' do
272
+ uri_for("http://foo.com:81/bar").should eq("http://foo.com:81/bar")
273
+ end
274
+
275
+ it 'does not remove a non-standard https port' do
276
+ uri_for("https://foo.com:442/bar").should eq("https://foo.com:442/bar")
277
+ end
247
278
  end
248
279
 
280
+ describe "#fiber_aware" do
281
+ it 'adds a #proceed method that yields in a fiber' do
282
+ fiber = Fiber.new do |request|
283
+ request.proceed
284
+ :done
285
+ end
286
+
287
+ fiber.resume(subject.fiber_aware).should be_nil
288
+ fiber.resume.should eq(:done)
289
+ end
290
+
291
+ it 'can be cast to a proc' do
292
+ request = subject.fiber_aware
293
+ request.should_receive(:proceed)
294
+ lambda(&request).call
295
+ end
296
+
297
+ it 'returns the request' do
298
+ subject.fiber_aware.should be(subject)
299
+ end
300
+ end if RUBY_VERSION > '1.9'
301
+
249
302
  it_behaves_like 'a header normalizer' do
250
303
  def with_headers(headers)
251
304
  described_class.new(:get, 'http://example.com/', nil, headers)
@@ -301,6 +354,13 @@ module VCR
301
354
  inst.update_content_length_header
302
355
  }.to change { inst.headers[header] }.from(['3']).to(['0'])
303
356
  end
357
+
358
+ it 'sets the header according to RFC 2616 based on the number of bytes (not the number of characters)' do
359
+ inst = instance('aؼ', '2') # the second char is a double byte char
360
+ expect {
361
+ inst.update_content_length_header
362
+ }.to change { inst.headers[header] }.from(['2']).to(['3'])
363
+ end
304
364
  end
305
365
  end
306
366
  end
@@ -1,5 +1,37 @@
1
1
  require 'spec_helper'
2
2
 
3
+ RSpec.configure do |config|
4
+ config.before(:suite) do
5
+ VCR.configuration.configure_rspec_metadata!
6
+ end
7
+ end
8
+
9
+ describe VCR::RSpec::Metadata, :skip_vcr_reset do
10
+ before(:all) { VCR.reset! }
11
+ after(:each) { VCR.reset! }
12
+
13
+ context 'an example group', :vcr do
14
+ context 'with a nested example group' do
15
+ it 'uses a cassette for any examples' do
16
+ VCR.current_cassette.name.split('/').should eq([
17
+ 'VCR::RSpec::Metadata',
18
+ 'an example group',
19
+ 'with a nested example group',
20
+ 'uses a cassette for any examples'
21
+ ])
22
+ end
23
+ end
24
+ end
25
+
26
+ it 'allows the cassette name to be overriden', :vcr => { :cassette_name => 'foo' } do
27
+ VCR.current_cassette.name.should eq('foo')
28
+ end
29
+
30
+ it 'allows the cassette options to be set', :vcr => { :match_requests_on => [:method] } do
31
+ VCR.current_cassette.match_requests_on.should eq([:method])
32
+ end
33
+ end
34
+
3
35
  describe VCR::RSpec::Macros do
4
36
  extend described_class
5
37
 
@@ -17,76 +17,86 @@ describe VCR::Hooks do
17
17
  it 'clears all hooks' do
18
18
  subject.before_foo { invocations << :callback }
19
19
  subject.clear_hooks
20
- subject.invoke_hook(:before_foo, nil)
20
+ subject.invoke_hook(:before_foo)
21
21
  invocations.should be_empty
22
22
  end
23
23
  end
24
24
 
25
25
  describe '#invoke_hook(:before_foo)' do
26
- context 'with a tag argument' do
27
- it 'invokes each of the :before_foo callbacks with a matching tag' do
28
- subject.before_foo(:green) { invocations << :callback_1 }
29
- subject.before_foo(:green) { invocations << :callback_2 }
30
-
31
- invocations.should be_empty
32
- subject.invoke_hook(:before_foo, :green)
33
- invocations.should eq([:callback_1, :callback_2])
34
- end
35
-
36
- it 'invokes each of the :before_foo callbacks with no tag' do
37
- subject.before_foo { invocations << :no_tag_1 }
38
- subject.before_foo { invocations << :no_tag_2 }
39
-
40
- subject.invoke_hook(:before_foo, :green)
41
- invocations.should eq([:no_tag_1, :no_tag_2])
42
- end
43
-
44
- it 'does not invoke any callbacks with a different tag' do
45
- subject.before_foo(:blue) { invocations << :blue_callback }
46
- subject.invoke_hook(:before_foo, :green)
47
- invocations.should be_empty
48
- end
26
+ it 'maps the return value of each callback' do
27
+ subject.before_foo { 17 }
28
+ subject.before_foo { 12 }
29
+ subject.invoke_hook(:before_foo).should eq([17, 12])
49
30
  end
50
31
 
51
- context 'without a tag argument' do
52
- it 'invokes each of the :before_foo callbacks' do
53
- subject.before_foo { invocations << :callback_1 }
54
- subject.before_foo { invocations << :callback_2 }
55
-
56
- invocations.should be_empty
57
- subject.invoke_hook(:before_foo, nil)
58
- invocations.should eq([:callback_1, :callback_2])
59
- end
60
-
61
- it 'does not invoke :before_bar callbacks' do
62
- subject.before_bar { invocations << :bar_callback }
63
- subject.invoke_hook(:before_foo, nil)
64
- invocations.should be_empty
65
- end
66
-
67
- it 'does not invoke any tagged callbacks' do
68
- subject.before_foo(:blue) { invocations << :blue_callback }
69
- subject.invoke_hook(:before_foo, nil)
70
- invocations.should be_empty
71
- end
72
-
73
- it 'passes along the provided arguments to the callback' do
74
- subject.before_foo(&lambda { |a, b| invocations << [a, b] })
75
- subject.invoke_hook(:before_foo, nil, :arg1, :arg2)
76
- invocations.flatten.should eq([:arg1, :arg2])
77
- end
78
-
79
- it 'only passes along 1 argument when the block accepts only 1 arguments' do
80
- subject.before_foo(&lambda { |a| invocations << a })
81
- subject.invoke_hook(:before_foo, nil, :arg1, :arg2)
82
- invocations.flatten.should eq([:arg1])
83
- end
84
-
85
- it 'passes along all arguments when the block accepts a variable number of args' do
86
- subject.before_foo(&lambda { |*a| invocations << a })
87
- subject.invoke_hook(:before_foo, nil, :arg1, :arg2)
88
- invocations.flatten.should eq([:arg1, :arg2])
89
- end
32
+ it 'invokes each of the :before_foo callbacks' do
33
+ subject.before_foo { invocations << :callback_1 }
34
+ subject.before_foo { invocations << :callback_2 }
35
+
36
+ invocations.should be_empty
37
+ subject.invoke_hook(:before_foo)
38
+ invocations.should eq([:callback_1, :callback_2])
39
+ end
40
+
41
+ it 'does not invoke :before_bar callbacks' do
42
+ subject.before_bar { invocations << :bar_callback }
43
+ subject.invoke_hook(:before_foo)
44
+ invocations.should be_empty
45
+ end
46
+
47
+ it 'does not invoke any tagged callbacks' do
48
+ subject.before_foo(:blue) { invocations << :blue_callback }
49
+ subject.invoke_hook(:before_foo)
50
+ invocations.should be_empty
51
+ end
52
+
53
+ it 'passes along the provided arguments to the callback' do
54
+ subject.before_foo(&lambda { |a, b| invocations << [a, b] })
55
+ subject.invoke_hook(:before_foo, :arg1, :arg2)
56
+ invocations.flatten.should eq([:arg1, :arg2])
57
+ end
58
+
59
+ it 'only passes along 1 argument when the block accepts only 1 arguments' do
60
+ subject.before_foo(&lambda { |a| invocations << a })
61
+ subject.invoke_hook(:before_foo, :arg1, :arg2)
62
+ invocations.flatten.should eq([:arg1])
63
+ end
64
+
65
+ it 'passes along all arguments when the block accepts a variable number of args' do
66
+ subject.before_foo(&lambda { |*a| invocations << a })
67
+ subject.invoke_hook(:before_foo, :arg1, :arg2)
68
+ invocations.flatten.should eq([:arg1, :arg2])
69
+ end
70
+ end
71
+
72
+ describe "#invoke_tagged_hook(:before_foo, tag)" do
73
+ it 'invokes each of the :before_foo callbacks with a matching tag' do
74
+ subject.before_foo(:green) { invocations << :callback_1 }
75
+ subject.before_foo(:green) { invocations << :callback_2 }
76
+
77
+ invocations.should be_empty
78
+ subject.invoke_tagged_hook(:before_foo, :green)
79
+ invocations.should eq([:callback_1, :callback_2])
80
+ end
81
+
82
+ it 'invokes each of the :before_foo callbacks with no tag' do
83
+ subject.before_foo { invocations << :no_tag_1 }
84
+ subject.before_foo { invocations << :no_tag_2 }
85
+
86
+ subject.invoke_hook(:before_foo, :green)
87
+ invocations.should eq([:no_tag_1, :no_tag_2])
88
+ end
89
+
90
+ it 'does not invoke any callbacks with a different tag' do
91
+ subject.before_foo(:blue) { invocations << :blue_callback }
92
+ subject.invoke_tagged_hook(:before_foo, :green)
93
+ invocations.should be_empty
94
+ end
95
+
96
+ it 'passes along the provided arguments to the callback' do
97
+ subject.before_foo(:green, &lambda { |a, b| invocations << [a, b] })
98
+ subject.invoke_tagged_hook(:before_foo, :green, :arg1, :arg2)
99
+ invocations.flatten.should eq([:arg1, :arg2])
90
100
  end
91
101
  end
92
102
  end