webmock 3.0.1 → 3.1.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 +4 -4
- data/.travis.yml +7 -7
- data/CHANGELOG.md +45 -0
- data/README.md +16 -2
- data/lib/webmock.rb +3 -0
- data/lib/webmock/api.rb +8 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +1 -1
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +1 -1
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +7 -1
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +4 -0
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +1 -1
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +5 -3
- data/lib/webmock/http_lib_adapters/net_http.rb +2 -2
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +2 -2
- data/lib/webmock/matchers/any_arg_matcher.rb +13 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +21 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +15 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +4 -23
- data/lib/webmock/rack_response.rb +1 -1
- data/lib/webmock/request_execution_verifier.rb +2 -3
- data/lib/webmock/request_pattern.rb +9 -2
- data/lib/webmock/request_registry.rb +1 -1
- data/lib/webmock/request_signature.rb +1 -1
- data/lib/webmock/request_signature_snippet.rb +4 -4
- data/lib/webmock/stub_request_snippet.rb +2 -2
- data/lib/webmock/util/headers.rb +2 -2
- data/lib/webmock/util/query_mapper.rb +3 -3
- data/lib/webmock/version.rb +1 -1
- data/minitest/webmock_spec.rb +2 -2
- data/spec/acceptance/http_rb/http_rb_spec.rb +9 -0
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +1 -1
- data/spec/acceptance/httpclient/httpclient_spec.rb +8 -1
- data/spec/acceptance/net_http/net_http_shared.rb +1 -1
- data/spec/acceptance/net_http/net_http_spec.rb +15 -1
- data/spec/acceptance/patron/patron_spec_helper.rb +1 -1
- data/spec/acceptance/shared/request_expectations.rb +7 -0
- data/spec/acceptance/shared/stubbing_requests.rb +5 -0
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +1 -1
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +1 -1
- data/spec/unit/api_spec.rb +84 -3
- data/spec/unit/matchers/hash_excluding_matcher_spec.rb +61 -0
- data/spec/unit/request_execution_verifier_spec.rb +12 -12
- data/test/shared_test.rb +15 -2
- metadata +44 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ba7b559bad31fd1150447c4895e4517a96e5c0b
|
4
|
+
data.tar.gz: 6682c3a0689f7aaf06b11cef43e170d584694187
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f77249e99b5553be7f9afea5de6112c7e63526c4c6ca42124bfa5089061b64eb469d927f903bf37d54245213b66d2217ee8112863848108dc262d995ca64c1d3
|
7
|
+
data.tar.gz: 779df5762aa1d72513d4cae0221b44e1dc92dee9b698db5ae6daf92fe12c29fb29d88af04968baabefe186ca9d51f1c564da89aa4c1e53fb31f55ead0f72d008
|
data/.travis.yml
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
+
before_install:
|
2
|
+
- gem update bundler
|
3
|
+
|
1
4
|
rvm:
|
2
|
-
- 2.
|
3
|
-
- 2.
|
4
|
-
- 2.2
|
5
|
-
- 2.2.3
|
6
|
-
- 2.3.0
|
7
|
-
- 2.4.0
|
5
|
+
- 2.2.8
|
6
|
+
- 2.3.5
|
7
|
+
- 2.4.2
|
8
8
|
- rbx-2
|
9
9
|
- ruby-head
|
10
10
|
- jruby-9.0.5.0
|
11
|
-
- jruby-9.1.
|
11
|
+
- jruby-9.1.13.0
|
12
12
|
- jruby-head
|
13
13
|
matrix:
|
14
14
|
allow_failures:
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,50 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 3.1.0
|
4
|
+
|
5
|
+
* http.rb 3.0.0 compatibility
|
6
|
+
|
7
|
+
Thanks to [Piotr Boniecki](https://github.com/Bonias)
|
8
|
+
|
9
|
+
* Typhoeus 1.3.0 support
|
10
|
+
|
11
|
+
Thanks to [NARUSE, Yui](https://github.com/nurse)
|
12
|
+
|
13
|
+
* Added support for matching partial query params using hash_excluding
|
14
|
+
|
15
|
+
stub_request(:get, "www.example.com").
|
16
|
+
with(query: hash_excluding({"a" => "b"}))
|
17
|
+
|
18
|
+
RestClient.get("http://www.example.com/?a=b") # ===> Failure
|
19
|
+
RestClient.get("http://www.example.com/?a=c") # ===> Success
|
20
|
+
|
21
|
+
Thanks to [Olexandr Hoshylyk](https://github.com/Warrior109)
|
22
|
+
|
23
|
+
* Added MRI 2.3+ frozen string literal compatibility
|
24
|
+
|
25
|
+
Thanks to [Pat Allan](https://github.com/pat)
|
26
|
+
|
27
|
+
* Ensured that HTTPClient adapter does not yield block on empty response body if a block is provided
|
28
|
+
|
29
|
+
Thanks to [NARUSE, Yui](https://github.com/nurse)
|
30
|
+
|
31
|
+
* Fixed issue with `to_timeout` incorrectly raising `HTTP::ConnectionError` instead of `HTTP::TimeoutError` when using http.rb
|
32
|
+
|
33
|
+
Thanks to [Rick Song](https://github.com/RickCSong)
|
34
|
+
|
35
|
+
* Fixed problem with `response.connection.close` method being undefined when using http.rb
|
36
|
+
|
37
|
+
Thanks to [Janko Marohnić](https://github.com/janko-m)
|
38
|
+
|
39
|
+
* Fixed problem with matching Net::HTTP request header values assigned as numbers.
|
40
|
+
|
41
|
+
Thanks to [Felipe Constantino de Oliveira](https://github.com/felipecdo) for reporting the issue.
|
42
|
+
|
43
|
+
* Fixed problem with Net::HTTP adapter converting empty response body to nil for non 204 responses.
|
44
|
+
|
45
|
+
Thanks to [Jeffrey Charles](https://github.com/jeffcharles) for reporting the issue.
|
46
|
+
|
47
|
+
|
3
48
|
## 3.0.1
|
4
49
|
|
5
50
|
* Suppressed \`warning: \`&' interpreted as argument prefix\`
|
data/README.md
CHANGED
@@ -32,8 +32,6 @@ Supported HTTP libraries
|
|
32
32
|
Supported Ruby Interpreters
|
33
33
|
---------------------------
|
34
34
|
|
35
|
-
* MRI 2.0
|
36
|
-
* MRI 2.1
|
37
35
|
* MRI 2.2
|
38
36
|
* MRI 2.3
|
39
37
|
* MRI 2.4
|
@@ -273,6 +271,16 @@ stub_request(:get, "www.example.com").
|
|
273
271
|
RestClient.get("http://www.example.com/?a[]=b&a[]=c&x=1") # ===> Success
|
274
272
|
```
|
275
273
|
|
274
|
+
### Matching partial query params using hash_excluding
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
stub_request(:get, "www.example.com").
|
278
|
+
with(query: hash_excluding({"a" => "b"}))
|
279
|
+
|
280
|
+
RestClient.get("http://www.example.com/?a=b") # ===> Failure
|
281
|
+
RestClient.get("http://www.example.com/?a=c") # ===> Success
|
282
|
+
```
|
283
|
+
|
276
284
|
### Stubbing with custom response
|
277
285
|
|
278
286
|
```ruby
|
@@ -1035,6 +1043,12 @@ People who submitted patches and new features or suggested improvements. Many th
|
|
1035
1043
|
* George Ulmer
|
1036
1044
|
* Christof Koenig
|
1037
1045
|
* Chung-Yi Chi
|
1046
|
+
* Olexandr Hoshylyk
|
1047
|
+
* Janko Marohnić
|
1048
|
+
* Pat Allan
|
1049
|
+
* Rick Song
|
1050
|
+
* NARUSE, Yui
|
1051
|
+
* Piotr Boniecki
|
1038
1052
|
|
1039
1053
|
For a full list of contributors you can visit the
|
1040
1054
|
[contributors](https://github.com/bblimke/webmock/contributors) page.
|
data/lib/webmock.rb
CHANGED
@@ -18,7 +18,10 @@ require 'webmock/util/json'
|
|
18
18
|
require 'webmock/util/version_checker'
|
19
19
|
require 'webmock/util/hash_validator'
|
20
20
|
|
21
|
+
require 'webmock/matchers/hash_argument_matcher'
|
22
|
+
require 'webmock/matchers/hash_excluding_matcher'
|
21
23
|
require 'webmock/matchers/hash_including_matcher'
|
24
|
+
require 'webmock/matchers/any_arg_matcher'
|
22
25
|
|
23
26
|
require 'webmock/request_pattern'
|
24
27
|
require 'webmock/request_signature'
|
data/lib/webmock/api.rb
CHANGED
@@ -54,6 +54,14 @@ module WebMock
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
+
def hash_excluding(*args)
|
58
|
+
if defined?(super)
|
59
|
+
super
|
60
|
+
else
|
61
|
+
WebMock::Matchers::HashExcludingMatcher.new(anythingize_lonely_keys(*args))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
57
65
|
def remove_request_stub(stub)
|
58
66
|
WebMock::StubRegistry.instance.remove_request_stub(stub)
|
59
67
|
end
|
@@ -153,7 +153,7 @@ if defined?(Curl)
|
|
153
153
|
@body_str = webmock_response.body
|
154
154
|
@response_code = webmock_response.status[0]
|
155
155
|
|
156
|
-
@header_str = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}\r\n"
|
156
|
+
@header_str = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}\r\n".dup
|
157
157
|
|
158
158
|
@on_debug.call(@header_str, 1) if defined?( @on_debug )
|
159
159
|
|
@@ -1,9 +1,15 @@
|
|
1
1
|
module HTTP
|
2
2
|
class Request
|
3
3
|
def webmock_signature
|
4
|
+
request_body = if defined?(HTTP::Request::Body)
|
5
|
+
''.tap { |string| body.each { |part| string << part } }
|
6
|
+
else
|
7
|
+
body
|
8
|
+
end
|
9
|
+
|
4
10
|
::WebMock::RequestSignature.new(verb, uri.to_s, {
|
5
11
|
headers: headers.to_h,
|
6
|
-
body:
|
12
|
+
body: request_body
|
7
13
|
})
|
8
14
|
end
|
9
15
|
end
|
@@ -43,7 +43,7 @@ module HTTP
|
|
43
43
|
|
44
44
|
def raise_timeout_error
|
45
45
|
raise Errno::ETIMEDOUT if HTTP::VERSION < "1.0.0"
|
46
|
-
raise HTTP::
|
46
|
+
raise HTTP::TimeoutError, "connection error: #{Errno::ETIMEDOUT.new}"
|
47
47
|
end
|
48
48
|
|
49
49
|
def perform
|
@@ -75,8 +75,10 @@ if defined?(::HTTPClient)
|
|
75
75
|
elsif block
|
76
76
|
body = ''
|
77
77
|
do_get_block_without_webmock(req, proxy, conn) do |http_res, chunk|
|
78
|
-
|
79
|
-
|
78
|
+
if chunk && chunk.bytesize > 0
|
79
|
+
body += chunk
|
80
|
+
block.call(http_res, chunk)
|
81
|
+
end
|
80
82
|
end
|
81
83
|
else
|
82
84
|
do_get_block_without_webmock(req, proxy, conn)
|
@@ -117,7 +119,7 @@ if defined?(::HTTPClient)
|
|
117
119
|
raise HTTPClient::TimeoutError if webmock_response.should_timeout
|
118
120
|
webmock_response.raise_error_if_any
|
119
121
|
|
120
|
-
block.call(response, body) if block
|
122
|
+
block.call(response, body) if block && body && body.bytesize > 0
|
121
123
|
|
122
124
|
response
|
123
125
|
end
|
@@ -154,7 +154,7 @@ module WebMock
|
|
154
154
|
def build_net_http_response(webmock_response, &block)
|
155
155
|
response = Net::HTTPResponse.send(:response_class, webmock_response.status[0].to_s).new("1.0", webmock_response.status[0].to_s, webmock_response.status[1])
|
156
156
|
body = webmock_response.body
|
157
|
-
body = nil if
|
157
|
+
body = nil if webmock_response.status[0].to_s == '204'
|
158
158
|
|
159
159
|
response.instance_variable_set(:@body, body)
|
160
160
|
webmock_response.headers.to_a.each do |name, values|
|
@@ -258,7 +258,7 @@ module Net #:nodoc: all
|
|
258
258
|
class WebMockNetBufferedIO < BufferedIO
|
259
259
|
def initialize(io, read_timeout: 60, continue_timeout: nil, debug_output: nil)
|
260
260
|
@read_timeout = read_timeout
|
261
|
-
@rbuf = ''
|
261
|
+
@rbuf = ''.dup
|
262
262
|
@debug_output = debug_output
|
263
263
|
|
264
264
|
@io = case io
|
@@ -106,11 +106,11 @@ if defined?(::Patron)
|
|
106
106
|
header_data = ([status_line] + header_fields).join("\r\n")
|
107
107
|
|
108
108
|
::Patron::Response.new(
|
109
|
-
"",
|
109
|
+
"".dup,
|
110
110
|
webmock_response.status[0],
|
111
111
|
0,
|
112
112
|
header_data,
|
113
|
-
webmock_response.body,
|
113
|
+
webmock_response.body.dup,
|
114
114
|
default_response_charset
|
115
115
|
)
|
116
116
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module WebMock
|
2
|
+
module Matchers
|
3
|
+
# Base class for Hash matchers
|
4
|
+
# https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/argument_matchers.rb
|
5
|
+
class HashArgumentMatcher
|
6
|
+
def initialize(expected)
|
7
|
+
@expected = Hash[WebMock::Util::HashKeysStringifier.stringify_keys!(expected, deep: true).sort]
|
8
|
+
end
|
9
|
+
|
10
|
+
def ==(_actual, &block)
|
11
|
+
@expected.all?(&block)
|
12
|
+
rescue NoMethodError
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.from_rspec_matcher(matcher)
|
17
|
+
new(matcher.instance_variable_get(:@expected))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module WebMock
|
2
|
+
module Matchers
|
3
|
+
# this is a based on RSpec::Mocks::ArgumentMatchers::HashExcludingMatcher
|
4
|
+
# https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/argument_matchers.rb
|
5
|
+
class HashExcludingMatcher < HashArgumentMatcher
|
6
|
+
def ==(actual)
|
7
|
+
super { |key, value| !actual.key?(key) || value != actual[key] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def inspect
|
11
|
+
"hash_excluding(#{@expected.inspect})"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,14 +1,10 @@
|
|
1
1
|
module WebMock
|
2
2
|
module Matchers
|
3
|
-
#this is a based on RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher
|
4
|
-
#https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/argument_matchers.rb
|
5
|
-
class HashIncludingMatcher
|
6
|
-
def initialize(expected)
|
7
|
-
@expected = Hash[WebMock::Util::HashKeysStringifier.stringify_keys!(expected, deep: true).sort]
|
8
|
-
end
|
9
|
-
|
3
|
+
# this is a based on RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher
|
4
|
+
# https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/argument_matchers.rb
|
5
|
+
class HashIncludingMatcher < HashArgumentMatcher
|
10
6
|
def ==(actual)
|
11
|
-
|
7
|
+
super { |key, value| actual.key?(key) && value === actual[key] }
|
12
8
|
rescue NoMethodError
|
13
9
|
false
|
14
10
|
end
|
@@ -16,21 +12,6 @@ module WebMock
|
|
16
12
|
def inspect
|
17
13
|
"hash_including(#{@expected.inspect})"
|
18
14
|
end
|
19
|
-
|
20
|
-
def self.from_rspec_matcher(matcher)
|
21
|
-
new(matcher.instance_variable_get(:@expected))
|
22
|
-
end
|
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
15
|
end
|
34
|
-
|
35
16
|
end
|
36
17
|
end
|
@@ -53,9 +53,8 @@ module WebMock
|
|
53
53
|
|
54
54
|
def failure_message_phrase(is_negated=false)
|
55
55
|
negation = is_negated ? "was not" : "was"
|
56
|
-
|
57
|
-
|
58
|
-
text
|
56
|
+
"The request #{request_pattern} #{negation} expected to execute #{quantity_phrase(is_negated)}but it executed #{times(times_executed)}" +
|
57
|
+
self.class.executed_requests_message
|
59
58
|
end
|
60
59
|
|
61
60
|
def quantity_phrase(is_negated=false)
|
@@ -4,6 +4,10 @@ module WebMock
|
|
4
4
|
def rSpecHashIncludingMatcher?(matcher)
|
5
5
|
matcher.class.name =~ /R?Spec::Mocks::ArgumentMatchers::HashIncludingMatcher/
|
6
6
|
end
|
7
|
+
|
8
|
+
def rSpecHashExcludingMatcher?(matcher)
|
9
|
+
matcher.class.name =~ /R?Spec::Mocks::ArgumentMatchers::HashExcludingMatcher/
|
10
|
+
end
|
7
11
|
end
|
8
12
|
|
9
13
|
class RequestPattern
|
@@ -37,7 +41,7 @@ module WebMock
|
|
37
41
|
end
|
38
42
|
|
39
43
|
def to_s
|
40
|
-
string = "#{@method_pattern.to_s.upcase}"
|
44
|
+
string = "#{@method_pattern.to_s.upcase}".dup
|
41
45
|
string << " #{@uri_pattern.to_s}"
|
42
46
|
string << " with body #{@body_pattern.to_s}" if @body_pattern
|
43
47
|
string << " with headers #{@headers_pattern.to_s}" if @headers_pattern
|
@@ -115,10 +119,13 @@ module WebMock
|
|
115
119
|
def add_query_params(query_params)
|
116
120
|
@query_params = if query_params.is_a?(Hash)
|
117
121
|
query_params
|
118
|
-
elsif query_params.is_a?(WebMock::Matchers::HashIncludingMatcher)
|
122
|
+
elsif query_params.is_a?(WebMock::Matchers::HashIncludingMatcher) \
|
123
|
+
|| query_params.is_a?(WebMock::Matchers::HashExcludingMatcher)
|
119
124
|
query_params
|
120
125
|
elsif rSpecHashIncludingMatcher?(query_params)
|
121
126
|
WebMock::Matchers::HashIncludingMatcher.from_rspec_matcher(query_params)
|
127
|
+
elsif rSpecHashExcludingMatcher?(query_params)
|
128
|
+
WebMock::Matchers::HashExcludingMatcher.from_rspec_matcher(query_params)
|
122
129
|
else
|
123
130
|
WebMock::Util::QueryMapper.query_to_values(query_params, notation: Config.instance.query_values_notation)
|
124
131
|
end
|
@@ -23,7 +23,7 @@ module WebMock
|
|
23
23
|
if requested_signatures.hash.empty?
|
24
24
|
"No requests were made."
|
25
25
|
else
|
26
|
-
text = ""
|
26
|
+
text = "".dup
|
27
27
|
self.requested_signatures.each do |request_signature, times_executed|
|
28
28
|
text << "#{request_signature} was made #{times_executed} time#{times_executed == 1 ? '' : 's' }\n"
|
29
29
|
end
|
@@ -12,7 +12,7 @@ module WebMock
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def to_s
|
15
|
-
string = "#{self.method.to_s.upcase}"
|
15
|
+
string = "#{self.method.to_s.upcase}".dup
|
16
16
|
string << " #{WebMock::Util::URI.strip_default_port_from_uri_string(self.uri.to_s)}"
|
17
17
|
string << " with body '#{body.to_s}'" if body && body.to_s != ''
|
18
18
|
if headers && !headers.empty?
|
@@ -13,14 +13,14 @@ module WebMock
|
|
13
13
|
def stubbing_instructions
|
14
14
|
return unless WebMock.show_stubbing_instructions?
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
"You can stub this request with the following snippet:\n\n" +
|
17
|
+
WebMock::StubRequestSnippet.new(request_stub).to_s
|
18
18
|
end
|
19
19
|
|
20
20
|
def request_stubs
|
21
21
|
return if WebMock::StubRegistry.instance.request_stubs.empty?
|
22
22
|
|
23
|
-
text = "registered request stubs:\n"
|
23
|
+
text = "registered request stubs:\n".dup
|
24
24
|
WebMock::StubRegistry.instance.request_stubs.each do |stub|
|
25
25
|
text << "\n#{WebMock::StubRequestSnippet.new(stub).to_s(false)}"
|
26
26
|
add_body_diff(stub, text) if WebMock.show_body_diff?
|
@@ -50,7 +50,7 @@ module WebMock
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def pretty_print_to_string(string_to_print)
|
53
|
-
StringIO.open("") do |stream|
|
53
|
+
StringIO.open("".dup) do |stream|
|
54
54
|
PP.pp(string_to_print, stream)
|
55
55
|
stream.rewind
|
56
56
|
stream.read
|