webmock 1.15.2 → 1.16.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.
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.16.0
4
+
5
+ * Allow a Pathname to be passed as a Response body
6
+
7
+ stub_request(:get, /example.com/).to_return(
8
+ body: Rails.root.join('test/fixtures/foo.txt')
9
+ )
10
+
11
+ Thanks to [Ben Pickles](https://github.com/benpickles)
12
+
13
+ * `hash_including` matcher can be initialized with empty keys to match any values.
14
+
15
+ stub_request(:post, "www.example.com").with(:body => hash_including(:a, :b => {'c'}))
16
+ RestClient.post('www.example.com', '{"a":"1","b":"c"}', :content_type => 'application/json')
17
+
18
+ Thanks to [Stefano Uliari](https://github.com/steookk)
19
+
3
20
  ## 1.15.2
4
21
 
5
22
  * Fixed `hash_including` to accept a splat of solitary keys.
data/README.md CHANGED
@@ -864,6 +864,7 @@ People who submitted patches and new features or suggested improvements. Many th
864
864
  * Brian D. Burns
865
865
  * Riley Strong
866
866
  * Tamir Duberstein
867
+ * Stefano Uliari
867
868
 
868
869
  For a full list of contributors you can visit the
869
870
  [contributors](https://github.com/bblimke/webmock/contributors) page.
@@ -35,11 +35,21 @@ module WebMock
35
35
  assert_request_not_requested(*args)
36
36
  end
37
37
 
38
- def hash_including(*expected)
38
+ # Similar to RSpec::Mocks::ArgumentMatchers#hash_including()
39
+ #
40
+ # Matches a hash that includes the specified key(s) or key/value pairs.
41
+ # Ignores any additional keys.
42
+ #
43
+ # @example
44
+ #
45
+ # object.should_receive(:message).with(hash_including(:key => val))
46
+ # object.should_receive(:message).with(hash_including(:key))
47
+ # object.should_receive(:message).with(hash_including(:key, :key2 => val2))
48
+ def hash_including(*args)
39
49
  if defined?(super)
40
50
  super
41
51
  else
42
- WebMock::Matchers::HashIncludingMatcher.new(expected)
52
+ WebMock::Matchers::HashIncludingMatcher.new(anythingize_lonely_keys(*args))
43
53
  end
44
54
  end
45
55
 
@@ -64,5 +74,12 @@ module WebMock
64
74
  WebMock::AssertionFailure.failure(verifier.negative_failure_message) unless verifier.does_not_match?
65
75
  end
66
76
 
77
+ #this is a based on RSpec::Mocks::ArgumentMatchers#anythingize_lonely_keys
78
+ def anythingize_lonely_keys(*args)
79
+ hash = args.last.class == Hash ? args.delete_at(-1) : {}
80
+ args.each { | arg | hash[arg] = WebMock::Matchers::AnyArgMatcher.new(nil) }
81
+ hash
82
+ end
83
+
67
84
  end
68
85
  end
@@ -148,6 +148,7 @@ if defined?(::HTTPClient)
148
148
  hdrs[header[0]] << header[1]
149
149
  hdrs
150
150
  end
151
+ headers = headers_from_session(uri).merge(headers)
151
152
 
152
153
  if (auth_cred = auth.get(req)) && auth.scheme == 'Basic'
153
154
  userinfo = WebMock::Util::Headers.decode_userinfo_from_header(auth_cred)
@@ -186,4 +187,28 @@ if defined?(::HTTPClient)
186
187
  webmock_request_signatures.delete_at(index)
187
188
  end
188
189
 
190
+ private
191
+
192
+ # some of the headers sent by HTTPClient are derived from
193
+ # the client session
194
+ def headers_from_session(uri)
195
+ session_headers = HTTP::Message::Headers.new
196
+ @session_manager.send(:open, uri).send(:set_header, MessageMock.new(session_headers))
197
+ session_headers.all.inject({}) do |hdrs, header|
198
+ hdrs[header[0]] = header[1]
199
+ hdrs
200
+ end
201
+ end
202
+
203
+ # Mocks a HTTPClient HTTP::Message
204
+ class MessageMock
205
+ attr_reader :header
206
+
207
+ def initialize(headers)
208
+ @header = headers
209
+ end
210
+
211
+ def http_version=(value);end
212
+ end
213
+
189
214
  end
@@ -97,7 +97,7 @@ module WebMock
97
97
  response = super(request, nil, &nil)
98
98
  after_request.call(response)
99
99
  }
100
- response = if started?
100
+ if started?
101
101
  if WebMock::Config.instance.net_http_connect_on_start
102
102
  super_with_after_request.call
103
103
  else
@@ -21,5 +21,16 @@ module WebMock
21
21
  new(matcher.instance_variable_get(:@expected))
22
22
  end
23
23
  end
24
+
25
+ #this is a based on RSpec::Mocks::ArgumentMatchers::AnyArgMatcher
26
+ class AnyArgMatcher
27
+ def initialize(ignore)
28
+ end
29
+
30
+ def ==(other)
31
+ true
32
+ end
33
+ end
34
+
24
35
  end
25
36
  end
@@ -100,10 +100,10 @@ module WebMock
100
100
  private
101
101
 
102
102
  def stringify_body!
103
- if @body.is_a?(IO)
103
+ if @body.is_a?(IO) || @body.is_a?(Pathname)
104
104
  io = @body
105
105
  @body = io.read
106
- io.close
106
+ io.close if io.respond_to?(:close)
107
107
  end
108
108
  end
109
109
 
@@ -1,3 +1,3 @@
1
1
  module WebMock
2
- VERSION = '1.15.2' unless defined?(::WebMock::VERSION)
2
+ VERSION = '1.16.0' unless defined?(::WebMock::VERSION)
3
3
  end
@@ -48,7 +48,7 @@ describe "Excon" do
48
48
  end
49
49
 
50
50
  let(:file) { File.new(__FILE__) }
51
- let(:file_contents) { File.new(__FILE__).read }
51
+ let(:file_contents) { File.read(__FILE__) }
52
52
 
53
53
  it 'handles file uploads correctly' do
54
54
  stub_request(:put, "http://example.com/upload").with(:body => file_contents)
@@ -127,4 +127,29 @@ describe "HTTPClient" do
127
127
  end
128
128
  end
129
129
 
130
+ context 'session headers' do
131
+
132
+ it "client sends a User-Agent header when given an agent_name explicitly to the client" do
133
+ user_agent = "Client/0.1"
134
+ stub_request(:get, "www.example.com").with(:headers => { 'User-agent' => "#{user_agent} #{HTTPClient::LIB_NAME}" })
135
+ HTTPClient.new(:agent_name => user_agent).get("www.example.com")
136
+ end
137
+
138
+ it "client sends the Accept, User-Agent, and Date by default" do
139
+ stub_request(:get, "www.example.com").with do |req|
140
+ req.headers["Accept"].should == "*/*"
141
+ req.headers["User-Agent"].should == "#{HTTPClient::DEFAULT_AGENT_NAME} #{HTTPClient::LIB_NAME}"
142
+ req.headers["Date"].should_not be_nil
143
+ end
144
+ http_request(:get, "www.example.com")
145
+ end
146
+
147
+ it "explicitly defined headers take precedence over session defaults" do
148
+ headers = { 'Accept' => 'foo/bar', 'User-Agent' => 'custom', 'Date' => 'today' }
149
+ stub_request(:get, "www.example.com").with(:headers => headers)
150
+ HTTPClient.new.get("www.example.com", nil, headers)
151
+ end
152
+
153
+ end
154
+
130
155
  end
@@ -92,13 +92,13 @@ shared_context "declared responses" do |*adapter_info|
92
92
  describe "when response body was declared as IO" do
93
93
  it "should return response body" do
94
94
  stub_request(:get, "www.example.com").to_return(:body => File.new(__FILE__))
95
- http_request(:get, "http://www.example.com/").body.should == File.new(__FILE__).read
95
+ http_request(:get, "http://www.example.com/").body.should == File.read(__FILE__)
96
96
  end
97
97
 
98
98
  it "should return response body if requested many times" do
99
99
  stub_request(:get, "www.example.com").to_return(:body => File.new(__FILE__))
100
100
  2.times do
101
- http_request(:get, "http://www.example.com/").body.should == File.new(__FILE__).read
101
+ http_request(:get, "http://www.example.com/").body.should == File.read(__FILE__)
102
102
  end
103
103
  end
104
104
 
@@ -199,7 +199,7 @@ shared_context "declared responses" do |*adapter_info|
199
199
 
200
200
  describe "when response was declared as a string with a raw response" do
201
201
  before(:each) do
202
- @input = File.new(CURL_EXAMPLE_OUTPUT_PATH).read
202
+ @input = File.read(CURL_EXAMPLE_OUTPUT_PATH)
203
203
  stub_request(:get, "www.example.com").to_return(@input)
204
204
  @response = http_request(:get, "http://www.example.com/")
205
205
  end
@@ -210,34 +210,62 @@ shared_examples_for "stubbing requests" do |*adapter_info|
210
210
  end
211
211
 
212
212
  describe "when body is declared as partial hash matcher" do
213
- before(:each) do
214
- stub_request(:post, "www.example.com").
215
- with(:body => hash_including({:a => '1', 'c' => {'d' => ['e', 'f']} }))
216
- end
213
+ subject(:request) { http_request( :post, "http://www.example.com/",
214
+ :body => 'a=1&c[d][]=e&c[d][]=f&b=five') }
217
215
 
218
- describe "for request with url encoded body" do
219
- it "should match request if hash matches body" do
220
- http_request(
221
- :post, "http://www.example.com/",
222
- :body => 'a=1&c[d][]=e&c[d][]=f&b=five').status.should == "200"
216
+ subject(:wrong_request) { http_request(:post, "http://www.example.com/",
217
+ :body => 'c[d][]=f&a=1&c[d][]=e').status }
218
+
219
+ describe "when using 'RSpec:Mocks::ArgumentMatchers#hash_including'" do
220
+ before(:each) do
221
+ stub_request(:post, "www.example.com").
222
+ with(:body => hash_including(:a, :c => {'d' => ['e', 'f']} ))
223
223
  end
224
224
 
225
- it "should not match if hash doesn't match url encoded body" do
226
- lambda {
225
+ describe "for request with url encoded body" do
226
+ it "should match request if hash matches body" do
227
+ expect(request.status).to eq("200")
228
+ end
229
+
230
+ it "should not match if hash doesn't match url encoded body" do
231
+ lambda { wrong_request }.should raise_error
232
+ end
233
+ end
234
+
235
+ describe "for request with json body and content type is set to json" do
236
+ it "should match if hash matches body" do
227
237
  http_request(
228
- :post, "http://www.example.com/",
229
- :body => 'c[d][]=f&a=1&c[d][]=e').status
230
- }.should raise_error
238
+ :post, "http://www.example.com/", :headers => {'Content-Type' => 'application/json'},
239
+ :body => "{\"a\":\"1\",\"c\":{\"d\":[\"e\",\"f\"]},\"b\":\"five\"}").status.should == "200"
240
+ end
231
241
  end
232
242
  end
233
243
 
234
- describe "for request with json body and content type is set to json" do
235
- it "should match if hash matches body" do
236
- http_request(
237
- :post, "http://www.example.com/", :headers => {'Content-Type' => 'application/json'},
238
- :body => "{\"a\":\"1\",\"c\":{\"d\":[\"e\",\"f\"]},\"b\":\"five\"}").status.should == "200"
244
+ describe "when using 'WebMock::API#hash_including'" do
245
+ before(:each) do
246
+ stub_request(:post, "www.example.com").
247
+ with(:body => WebMock::API.hash_including(:a, :c => {'d' => ['e', 'f']} ))
248
+ end
249
+
250
+ describe "for request with url encoded body" do
251
+ it "should match request if hash matches body" do
252
+ expect(request.status).to eq("200")
253
+ end
254
+
255
+ it "should not match if hash doesn't match url encoded body" do
256
+ lambda { wrong_request }.should raise_error
257
+ end
258
+ end
259
+
260
+ describe "for request with json body and content type is set to json" do
261
+ it "should match if hash matches body" do
262
+ http_request(
263
+ :post, "http://www.example.com/", :headers => {'Content-Type' => 'application/json'},
264
+ :body => "{\"a\":\"1\",\"c\":{\"d\":[\"e\",\"f\"]},\"b\":\"five\"}").status.should == "200"
265
+ end
239
266
  end
240
267
  end
268
+
241
269
  end
242
270
  end
243
271
 
@@ -17,7 +17,7 @@ require 'support/network_connection'
17
17
  require 'support/webmock_server'
18
18
  require 'support/my_rack_app'
19
19
 
20
- CURL_EXAMPLE_OUTPUT_PATH = File.expand_path(File.dirname(__FILE__)) + "/support/example_curl_output.txt" unless defined? CURL_EXAMPLE_OUTPUT_PATH
20
+ CURL_EXAMPLE_OUTPUT_PATH = File.expand_path('../support/example_curl_output.txt', __FILE__)
21
21
 
22
22
  RSpec.configure do |config|
23
23
  unless NetworkConnection.is_network_available?
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe WebMock::API do
4
+ describe '#hash_including' do
5
+
6
+ subject { klass.new.hash_including(args) }
7
+ let(:args) { {:data => :one} }
8
+
9
+ context 'when mixed into a class that does not define `hash_including`' do
10
+ let(:klass) do
11
+ Class.new do
12
+ include WebMock::API
13
+ end
14
+ end
15
+
16
+ it 'uses WebMock::Matchers::HashIncludingMatcher' do
17
+ expect(subject).to be_a(WebMock::Matchers::HashIncludingMatcher)
18
+ end
19
+
20
+ # by testing equality for HashIncludingMatcher (which stringifies the passed hash) we are
21
+ # testing HashIncludingMatcher.initialize behavior as well
22
+ context "when args correspond to an hash" do
23
+ it "creates 'HashIncludingMatcher'" do
24
+ expect(subject).to eq("data" => :one)
25
+ end
26
+ end
27
+
28
+ context "when args are one or many keys" do
29
+ subject {klass.new.hash_including(:foo, :bar)}
30
+ let(:anything) { WebMock::Matchers::AnyArgMatcher.new(nil) }
31
+
32
+ it "creates 'HashIncludingMatcher' with keys anythingized" do
33
+ expect(subject).to eq("foo" => anything, "bar" => anything )
34
+ end
35
+ end
36
+
37
+ context "when args are both keys and key/value pairs" do
38
+ subject {klass.new.hash_including(:foo, :bar, :data => :one)}
39
+ let(:anything) { WebMock::Matchers::AnyArgMatcher.new(nil) }
40
+
41
+ it "creates 'HashIncludingMatcher' with keys anythingized" do
42
+ expect(subject).to eq("foo" => anything, "bar" => anything, "data" => :one)
43
+ end
44
+ end
45
+
46
+ context "when args are an emtpy hash" do
47
+ subject {klass.new.hash_including({})}
48
+
49
+ it "creates 'HashIncludingMatcher' with an empty hash" do
50
+ expect(subject).to eq({})
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ context 'when mixed into a class with a parent that defines `hash_including`' do
57
+ subject {klass.new.hash_including(*args)}
58
+ let(:args) { %w(:foo, :bar, {:data => :one}) }
59
+ let(:klass) do
60
+ Class.new(
61
+ Class.new do
62
+ def hash_including(*args)
63
+ args
64
+ end
65
+ end
66
+ ) { include WebMock::API }
67
+ end
68
+
69
+ it 'uses super and passes the args untampered' do
70
+ expect(subject).to eq(args)
71
+ end
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ module WebMock
4
+ module Matchers
5
+
6
+ describe HashIncludingMatcher do
7
+
8
+ it "stringifies the given hash keys" do
9
+ expect(HashIncludingMatcher.new(:a => 1, :b => 2)).to eq("a" => 1, "b" => 2)
10
+ end
11
+
12
+ it "sorts elements in the hash" do
13
+ expect(HashIncludingMatcher.new(:b => 2, :a => 1)).to eq("a" => 1, "b" => 2)
14
+ end
15
+
16
+ it "describes itself properly" do
17
+ expect(HashIncludingMatcher.new(:a => 1).inspect).to eq "hash_including({\"a\"=>1})"
18
+ end
19
+
20
+ describe "success" do
21
+ it "matches the same hash" do
22
+ expect(HashIncludingMatcher.new("a" => 1, "b" => 2)).to eq("a" => 1, "b" => 2)
23
+ end
24
+
25
+ it "matches a hash with extra stuff" do
26
+ expect(HashIncludingMatcher.new(:a => 1)).to eq("a" => 1, "b" => 2)
27
+ end
28
+
29
+ describe "when matching anythingized keys" do
30
+ let(:anything) { WebMock::Matchers::AnyArgMatcher.new(nil) }
31
+
32
+ it "matches an int against anything()" do
33
+ expect(HashIncludingMatcher.new(:a => anything, :b => 2)).to eq({'a' => 1, 'b' => 2})
34
+ end
35
+
36
+ it "matches a string against anything()" do
37
+ expect(HashIncludingMatcher.new(:a => anything, :b => 2)).to eq({'a' => "1", 'b' => 2})
38
+ end
39
+
40
+ it "matches if the key is present" do
41
+ expect(HashIncludingMatcher.new(:a => anything)).to eq({'a' => 1, 'b' => 2})
42
+ end
43
+
44
+ it "matches if more keys are present" do
45
+ expect(HashIncludingMatcher.new(:a => anything, :b => anything)).to eq({'a' => 1, 'b' => 2, 'c' => 3})
46
+ end
47
+
48
+ it "matches if passed many keys and many key/value pairs" do
49
+ expect(HashIncludingMatcher.new(:a => anything, :b => anything, :c => 3, :e => 5)).to eq({'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5})
50
+ end
51
+ end
52
+
53
+ describe "when matching an empty hash" do
54
+ it "matches against any hash" do
55
+ expect(HashIncludingMatcher.new({})).to eq({:a => 1, :b => 2, :c => 3})
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "failing" do
61
+ it "does not match a non-hash" do
62
+ expect(HashIncludingMatcher.new(:a => 1)).not_to eq 1
63
+ end
64
+
65
+ it "does not match a hash with a missing key" do
66
+ expect(HashIncludingMatcher.new(:a => 1)).not_to eq('b' => 2)
67
+ end
68
+
69
+ it "does not match an empty hash with a given key" do
70
+ expect(HashIncludingMatcher.new(:a => 1)).not_to eq({})
71
+ end
72
+
73
+ it "does not match a hash with a missing key when one pair is matching" do
74
+ expect(HashIncludingMatcher.new(:a => 1, :b => 2)).not_to eq('b' => 2)
75
+ end
76
+
77
+ it "does not match a hash with an incorrect value" do
78
+ expect(HashIncludingMatcher.new(:a => 1, :b => 2)).not_to eq('a' => 1, 'b' => 3)
79
+ end
80
+
81
+ it "does not match when values are nil but keys are different" do
82
+ expect(HashIncludingMatcher.new(:a => nil)).not_to eq('b' => nil)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -111,15 +111,19 @@ describe WebMock::Response do
111
111
 
112
112
  it "should report content of a IO object if provided" do
113
113
  @response = WebMock::Response.new(:body => File.new(__FILE__))
114
- @response.body.should == File.new(__FILE__).read
114
+ @response.body.should == File.read(__FILE__)
115
115
  end
116
116
 
117
117
  it "should report many times content of a IO object if provided" do
118
118
  @response = WebMock::Response.new(:body => File.new(__FILE__))
119
- @response.body.should == File.new(__FILE__).read
120
- @response.body.should == File.new(__FILE__).read
119
+ @response.body.should == File.read(__FILE__)
120
+ @response.body.should == File.read(__FILE__)
121
121
  end
122
122
 
123
+ it "should work with Pathnames" do
124
+ @response = WebMock::Response.new(:body => Pathname.new(__FILE__))
125
+ @response.body.should == File.read(__FILE__)
126
+ end
123
127
  end
124
128
 
125
129
  describe "from raw response" do
@@ -157,7 +161,7 @@ describe WebMock::Response do
157
161
 
158
162
  describe "when input is String" do
159
163
  before(:each) do
160
- @input = File.new(CURL_EXAMPLE_OUTPUT_PATH).read
164
+ @input = File.read(CURL_EXAMPLE_OUTPUT_PATH)
161
165
  @response = WebMock::Response.new(@input)
162
166
  end
163
167
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webmock
3
3
  version: !ruby/object:Gem::Version
4
- hash: 47
4
+ hash: 87
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 15
9
- - 2
10
- version: 1.15.2
8
+ - 16
9
+ - 0
10
+ version: 1.16.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Bartosz Blimke
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-10-30 00:00:00 Z
18
+ date: 2013-11-17 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: addressable
@@ -291,10 +291,11 @@ files:
291
291
  - spec/support/my_rack_app.rb
292
292
  - spec/support/network_connection.rb
293
293
  - spec/support/webmock_server.rb
294
+ - spec/unit/api_spec.rb
294
295
  - spec/unit/errors_spec.rb
295
296
  - spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb
296
297
  - spec/unit/http_lib_adapters/http_lib_adapter_spec.rb
297
- - spec/unit/include_spec.rb
298
+ - spec/unit/matchers/hash_including_matcher_spec.rb
298
299
  - spec/unit/rack_response_spec.rb
299
300
  - spec/unit/request_execution_verifier_spec.rb
300
301
  - spec/unit/request_pattern_spec.rb
@@ -381,10 +382,11 @@ test_files:
381
382
  - spec/support/my_rack_app.rb
382
383
  - spec/support/network_connection.rb
383
384
  - spec/support/webmock_server.rb
385
+ - spec/unit/api_spec.rb
384
386
  - spec/unit/errors_spec.rb
385
387
  - spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb
386
388
  - spec/unit/http_lib_adapters/http_lib_adapter_spec.rb
387
- - spec/unit/include_spec.rb
389
+ - spec/unit/matchers/hash_including_matcher_spec.rb
388
390
  - spec/unit/rack_response_spec.rb
389
391
  - spec/unit/request_execution_verifier_spec.rb
390
392
  - spec/unit/request_pattern_spec.rb
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe WebMock::API do
4
- describe '#hash_including' do
5
- subject { klass.new.hash_including(*args) }
6
-
7
- let(:args) { %w(foo bar) }
8
-
9
- context 'when mixed into a class that does not define `hash_including`' do
10
- let(:klass) do
11
- Class.new do
12
- include WebMock::API
13
- end
14
- end
15
-
16
- it 'uses WebMock::Matchers::HashIncludingMatcher' do
17
- expect(subject).to be_a(WebMock::Matchers::HashIncludingMatcher)
18
- end
19
- end
20
-
21
- context 'when mixed into a class with a parent that defines `hash_including`' do
22
- let(:klass) do
23
- Class.new(
24
- Class.new do
25
- def hash_including(*args)
26
- args
27
- end
28
- end
29
- ) { include WebMock::API }
30
- end
31
-
32
- it 'uses super and passes the args untampered' do
33
- expect(subject).to eq(args)
34
- end
35
- end
36
- end
37
- end