webmock 3.0.1 → 3.20.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 +5 -5
- data/CHANGELOG.md +558 -2
- data/README.md +200 -42
- data/lib/webmock/api.rb +14 -0
- data/lib/webmock/assertion_failure.rb +2 -0
- data/lib/webmock/callback_registry.rb +2 -0
- data/lib/webmock/config.rb +2 -0
- data/lib/webmock/cucumber.rb +2 -0
- data/lib/webmock/deprecation.rb +2 -0
- data/lib/webmock/errors.rb +2 -0
- data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +223 -0
- data/lib/webmock/http_lib_adapters/curb_adapter.rb +21 -5
- data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +20 -9
- data/lib/webmock/http_lib_adapters/excon_adapter.rb +7 -2
- data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +2 -0
- data/lib/webmock/http_lib_adapters/http_rb/client.rb +4 -1
- data/lib/webmock/http_lib_adapters/http_rb/request.rb +19 -1
- data/lib/webmock/http_lib_adapters/http_rb/response.rb +29 -3
- data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +11 -3
- data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +9 -3
- data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +2 -0
- data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +30 -9
- data/lib/webmock/http_lib_adapters/manticore_adapter.rb +35 -15
- data/lib/webmock/http_lib_adapters/net_http.rb +38 -89
- data/lib/webmock/http_lib_adapters/net_http_response.rb +3 -1
- data/lib/webmock/http_lib_adapters/patron_adapter.rb +6 -4
- data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +18 -2
- data/lib/webmock/matchers/any_arg_matcher.rb +15 -0
- data/lib/webmock/matchers/hash_argument_matcher.rb +23 -0
- data/lib/webmock/matchers/hash_excluding_matcher.rb +17 -0
- data/lib/webmock/matchers/hash_including_matcher.rb +6 -23
- data/lib/webmock/minitest.rb +2 -0
- data/lib/webmock/rack_response.rb +3 -1
- data/lib/webmock/request_body_diff.rb +3 -1
- data/lib/webmock/request_execution_verifier.rb +4 -3
- data/lib/webmock/request_pattern.rb +132 -52
- data/lib/webmock/request_registry.rb +3 -1
- data/lib/webmock/request_signature.rb +5 -3
- data/lib/webmock/request_signature_snippet.rb +6 -4
- data/lib/webmock/request_stub.rb +34 -0
- data/lib/webmock/response.rb +22 -14
- data/lib/webmock/responses_sequence.rb +2 -0
- data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +2 -0
- data/lib/webmock/rspec/matchers/webmock_matcher.rb +2 -0
- data/lib/webmock/rspec/matchers.rb +2 -0
- data/lib/webmock/rspec.rb +12 -3
- data/lib/webmock/stub_registry.rb +28 -11
- data/lib/webmock/stub_request_snippet.rb +12 -6
- data/lib/webmock/test_unit.rb +3 -3
- data/lib/webmock/util/hash_counter.rb +15 -9
- data/lib/webmock/util/hash_keys_stringifier.rb +2 -0
- data/lib/webmock/util/hash_validator.rb +2 -0
- data/lib/webmock/util/headers.rb +39 -11
- data/lib/webmock/util/json.rb +3 -2
- data/lib/webmock/util/query_mapper.rb +11 -7
- data/lib/webmock/util/uri.rb +13 -11
- data/lib/webmock/util/values_stringifier.rb +22 -0
- data/lib/webmock/util/version_checker.rb +7 -5
- data/lib/webmock/version.rb +3 -1
- data/lib/webmock/webmock.rb +22 -3
- data/lib/webmock.rb +55 -48
- metadata +106 -175
- data/.gemtest +0 -0
- data/.gitignore +0 -34
- data/.rspec-tm +0 -2
- data/.travis.yml +0 -20
- data/Gemfile +0 -9
- data/Rakefile +0 -30
- data/minitest/test_helper.rb +0 -34
- data/minitest/test_webmock.rb +0 -9
- data/minitest/webmock_spec.rb +0 -60
- data/spec/acceptance/curb/curb_spec.rb +0 -466
- data/spec/acceptance/curb/curb_spec_helper.rb +0 -147
- data/spec/acceptance/em_http_request/em_http_request_spec.rb +0 -406
- data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +0 -77
- data/spec/acceptance/excon/excon_spec.rb +0 -75
- data/spec/acceptance/excon/excon_spec_helper.rb +0 -50
- data/spec/acceptance/http_rb/http_rb_spec.rb +0 -73
- data/spec/acceptance/http_rb/http_rb_spec_helper.rb +0 -51
- data/spec/acceptance/httpclient/httpclient_spec.rb +0 -210
- data/spec/acceptance/httpclient/httpclient_spec_helper.rb +0 -57
- data/spec/acceptance/manticore/manticore_spec.rb +0 -56
- data/spec/acceptance/manticore/manticore_spec_helper.rb +0 -35
- data/spec/acceptance/net_http/net_http_shared.rb +0 -153
- data/spec/acceptance/net_http/net_http_spec.rb +0 -317
- data/spec/acceptance/net_http/net_http_spec_helper.rb +0 -64
- data/spec/acceptance/net_http/real_net_http_spec.rb +0 -20
- data/spec/acceptance/patron/patron_spec.rb +0 -118
- data/spec/acceptance/patron/patron_spec_helper.rb +0 -54
- data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +0 -313
- data/spec/acceptance/shared/callbacks.rb +0 -147
- data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +0 -36
- data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +0 -95
- data/spec/acceptance/shared/precedence_of_stubs.rb +0 -15
- data/spec/acceptance/shared/request_expectations.rb +0 -916
- data/spec/acceptance/shared/returning_declared_responses.rb +0 -388
- data/spec/acceptance/shared/stubbing_requests.rb +0 -583
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +0 -135
- data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +0 -60
- data/spec/acceptance/webmock_shared.rb +0 -41
- data/spec/fixtures/test.txt +0 -1
- data/spec/quality_spec.rb +0 -84
- data/spec/spec_helper.rb +0 -48
- data/spec/support/example_curl_output.txt +0 -22
- data/spec/support/failures.rb +0 -9
- data/spec/support/my_rack_app.rb +0 -53
- data/spec/support/network_connection.rb +0 -19
- data/spec/support/webmock_server.rb +0 -69
- data/spec/unit/api_spec.rb +0 -75
- data/spec/unit/errors_spec.rb +0 -129
- data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +0 -17
- data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +0 -12
- data/spec/unit/matchers/hash_including_matcher_spec.rb +0 -87
- data/spec/unit/rack_response_spec.rb +0 -112
- data/spec/unit/request_body_diff_spec.rb +0 -90
- data/spec/unit/request_execution_verifier_spec.rb +0 -208
- data/spec/unit/request_pattern_spec.rb +0 -590
- data/spec/unit/request_registry_spec.rb +0 -95
- data/spec/unit/request_signature_snippet_spec.rb +0 -89
- data/spec/unit/request_signature_spec.rb +0 -155
- data/spec/unit/request_stub_spec.rb +0 -199
- data/spec/unit/response_spec.rb +0 -282
- data/spec/unit/stub_registry_spec.rb +0 -103
- data/spec/unit/stub_request_snippet_spec.rb +0 -95
- data/spec/unit/util/hash_counter_spec.rb +0 -39
- data/spec/unit/util/hash_keys_stringifier_spec.rb +0 -27
- data/spec/unit/util/headers_spec.rb +0 -28
- data/spec/unit/util/json_spec.rb +0 -33
- data/spec/unit/util/query_mapper_spec.rb +0 -144
- data/spec/unit/util/uri_spec.rb +0 -299
- data/spec/unit/util/version_checker_spec.rb +0 -65
- data/spec/unit/webmock_spec.rb +0 -11
- data/test/http_request.rb +0 -24
- data/test/shared_test.rb +0 -95
- data/test/test_helper.rb +0 -23
- data/test/test_webmock.rb +0 -6
- data/webmock.gemspec +0 -46
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
|
|
3
5
|
module RSpecMatcherDetector
|
|
4
6
|
def rSpecHashIncludingMatcher?(matcher)
|
|
5
7
|
matcher.class.name =~ /R?Spec::Mocks::ArgumentMatchers::HashIncludingMatcher/
|
|
6
8
|
end
|
|
9
|
+
|
|
10
|
+
def rSpecHashExcludingMatcher?(matcher)
|
|
11
|
+
matcher.class.name =~ /R?Spec::Mocks::ArgumentMatchers::HashExcludingMatcher/
|
|
12
|
+
end
|
|
7
13
|
end
|
|
8
14
|
|
|
9
15
|
class RequestPattern
|
|
@@ -20,7 +26,7 @@ module WebMock
|
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
def with(options = {}, &block)
|
|
23
|
-
raise ArgumentError.new('#with method invoked with no arguments. Either options hash or block must be specified.') if options.empty? && !block_given?
|
|
29
|
+
raise ArgumentError.new('#with method invoked with no arguments. Either options hash or block must be specified. Created a block with do..end? Try creating it with curly braces {} instead.') if options.empty? && !block_given?
|
|
24
30
|
assign_options(options)
|
|
25
31
|
@with_block = block
|
|
26
32
|
self
|
|
@@ -37,7 +43,7 @@ module WebMock
|
|
|
37
43
|
end
|
|
38
44
|
|
|
39
45
|
def to_s
|
|
40
|
-
string = "#{@method_pattern.to_s.upcase}"
|
|
46
|
+
string = "#{@method_pattern.to_s.upcase}".dup
|
|
41
47
|
string << " #{@uri_pattern.to_s}"
|
|
42
48
|
string << " with body #{@body_pattern.to_s}" if @body_pattern
|
|
43
49
|
string << " with headers #{@headers_pattern.to_s}" if @headers_pattern
|
|
@@ -76,6 +82,8 @@ module WebMock
|
|
|
76
82
|
URIRegexpPattern.new(uri)
|
|
77
83
|
elsif uri.is_a?(Addressable::Template)
|
|
78
84
|
URIAddressablePattern.new(uri)
|
|
85
|
+
elsif uri.respond_to?(:call)
|
|
86
|
+
URICallablePattern.new(uri)
|
|
79
87
|
else
|
|
80
88
|
URIStringPattern.new(uri)
|
|
81
89
|
end
|
|
@@ -103,11 +111,13 @@ module WebMock
|
|
|
103
111
|
include RSpecMatcherDetector
|
|
104
112
|
|
|
105
113
|
def initialize(pattern)
|
|
106
|
-
@pattern =
|
|
107
|
-
|
|
114
|
+
@pattern = if pattern.is_a?(Addressable::URI) \
|
|
115
|
+
|| pattern.is_a?(Addressable::Template)
|
|
116
|
+
pattern
|
|
117
|
+
elsif pattern.respond_to?(:call)
|
|
108
118
|
pattern
|
|
109
119
|
else
|
|
110
|
-
|
|
120
|
+
WebMock::Util::URI.normalize_uri(pattern)
|
|
111
121
|
end
|
|
112
122
|
@query_params = nil
|
|
113
123
|
end
|
|
@@ -115,65 +125,116 @@ module WebMock
|
|
|
115
125
|
def add_query_params(query_params)
|
|
116
126
|
@query_params = if query_params.is_a?(Hash)
|
|
117
127
|
query_params
|
|
118
|
-
elsif query_params.is_a?(WebMock::Matchers::HashIncludingMatcher)
|
|
128
|
+
elsif query_params.is_a?(WebMock::Matchers::HashIncludingMatcher) \
|
|
129
|
+
|| query_params.is_a?(WebMock::Matchers::HashExcludingMatcher)
|
|
119
130
|
query_params
|
|
120
131
|
elsif rSpecHashIncludingMatcher?(query_params)
|
|
121
132
|
WebMock::Matchers::HashIncludingMatcher.from_rspec_matcher(query_params)
|
|
133
|
+
elsif rSpecHashExcludingMatcher?(query_params)
|
|
134
|
+
WebMock::Matchers::HashExcludingMatcher.from_rspec_matcher(query_params)
|
|
122
135
|
else
|
|
123
136
|
WebMock::Util::QueryMapper.query_to_values(query_params, notation: Config.instance.query_values_notation)
|
|
124
137
|
end
|
|
125
138
|
end
|
|
126
139
|
|
|
140
|
+
def matches?(uri)
|
|
141
|
+
pattern_matches?(uri) && query_params_matches?(uri)
|
|
142
|
+
end
|
|
143
|
+
|
|
127
144
|
def to_s
|
|
128
|
-
str =
|
|
145
|
+
str = pattern_inspect
|
|
129
146
|
str += " with query params #{@query_params.inspect}" if @query_params
|
|
130
147
|
str
|
|
131
148
|
end
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
|
|
152
|
+
def pattern_inspect
|
|
153
|
+
@pattern.inspect
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def query_params_matches?(uri)
|
|
157
|
+
@query_params.nil? || @query_params == WebMock::Util::QueryMapper.query_to_values(uri.query, notation: Config.instance.query_values_notation)
|
|
158
|
+
end
|
|
132
159
|
end
|
|
133
160
|
|
|
134
|
-
class
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
161
|
+
class URICallablePattern < URIPattern
|
|
162
|
+
private
|
|
163
|
+
|
|
164
|
+
def pattern_matches?(uri)
|
|
165
|
+
@pattern.call(uri)
|
|
138
166
|
end
|
|
167
|
+
end
|
|
139
168
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
169
|
+
class URIRegexpPattern < URIPattern
|
|
170
|
+
private
|
|
171
|
+
|
|
172
|
+
def pattern_matches?(uri)
|
|
173
|
+
WebMock::Util::URI.variations_of_uri_as_strings(uri).any? { |u| u.match(@pattern) }
|
|
144
174
|
end
|
|
145
175
|
end
|
|
146
176
|
|
|
147
177
|
class URIAddressablePattern < URIPattern
|
|
148
|
-
def
|
|
178
|
+
def add_query_params(query_params)
|
|
179
|
+
@@add_query_params_warned ||= false
|
|
180
|
+
if not @@add_query_params_warned
|
|
181
|
+
@@add_query_params_warned = true
|
|
182
|
+
warn "WebMock warning: ignoring query params in RFC 6570 template and checking them with WebMock"
|
|
183
|
+
end
|
|
184
|
+
super(query_params)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
private
|
|
188
|
+
|
|
189
|
+
def pattern_matches?(uri)
|
|
149
190
|
if @query_params.nil?
|
|
150
191
|
# Let Addressable check the whole URI
|
|
151
|
-
|
|
192
|
+
matches_with_variations?(uri)
|
|
152
193
|
else
|
|
153
194
|
# WebMock checks the query, Addressable checks everything else
|
|
154
|
-
|
|
155
|
-
@query_params == WebMock::Util::QueryMapper.query_to_values(uri.query)
|
|
195
|
+
matches_with_variations?(uri.omit(:query))
|
|
156
196
|
end
|
|
157
197
|
end
|
|
158
198
|
|
|
159
|
-
def
|
|
160
|
-
|
|
161
|
-
super(query_params)
|
|
199
|
+
def pattern_inspect
|
|
200
|
+
@pattern.pattern.inspect
|
|
162
201
|
end
|
|
163
202
|
|
|
164
|
-
def
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
203
|
+
def matches_with_variations?(uri)
|
|
204
|
+
template =
|
|
205
|
+
begin
|
|
206
|
+
Addressable::Template.new(WebMock::Util::URI.heuristic_parse(@pattern.pattern))
|
|
207
|
+
rescue Addressable::URI::InvalidURIError
|
|
208
|
+
Addressable::Template.new(@pattern.pattern)
|
|
209
|
+
end
|
|
210
|
+
WebMock::Util::URI.variations_of_uri_as_strings(uri).any? { |u|
|
|
211
|
+
template_matches_uri?(template, u)
|
|
212
|
+
}
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def template_matches_uri?(template, uri)
|
|
216
|
+
template.match(uri)
|
|
217
|
+
rescue Addressable::URI::InvalidURIError
|
|
218
|
+
false
|
|
168
219
|
end
|
|
169
220
|
end
|
|
170
221
|
|
|
171
222
|
class URIStringPattern < URIPattern
|
|
172
|
-
def
|
|
223
|
+
def add_query_params(query_params)
|
|
224
|
+
super
|
|
225
|
+
if @query_params.is_a?(Hash) || @query_params.is_a?(String)
|
|
226
|
+
query_hash = (WebMock::Util::QueryMapper.query_to_values(@pattern.query, notation: Config.instance.query_values_notation) || {}).merge(@query_params)
|
|
227
|
+
@pattern.query = WebMock::Util::QueryMapper.values_to_query(query_hash, notation: WebMock::Config.instance.query_values_notation)
|
|
228
|
+
@query_params = nil
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
private
|
|
233
|
+
|
|
234
|
+
def pattern_matches?(uri)
|
|
173
235
|
if @pattern.is_a?(Addressable::URI)
|
|
174
236
|
if @query_params
|
|
175
|
-
uri.omit(:query) === @pattern
|
|
176
|
-
(@query_params.nil? || @query_params == WebMock::Util::QueryMapper.query_to_values(uri.query, notation: Config.instance.query_values_notation))
|
|
237
|
+
uri.omit(:query) === @pattern
|
|
177
238
|
else
|
|
178
239
|
uri === @pattern
|
|
179
240
|
end
|
|
@@ -182,19 +243,8 @@ module WebMock
|
|
|
182
243
|
end
|
|
183
244
|
end
|
|
184
245
|
|
|
185
|
-
def
|
|
186
|
-
|
|
187
|
-
if @query_params.is_a?(Hash) || @query_params.is_a?(String)
|
|
188
|
-
query_hash = (WebMock::Util::QueryMapper.query_to_values(@pattern.query, notation: Config.instance.query_values_notation) || {}).merge(@query_params)
|
|
189
|
-
@pattern.query = WebMock::Util::QueryMapper.values_to_query(query_hash, notation: WebMock::Config.instance.query_values_notation)
|
|
190
|
-
@query_params = nil
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def to_s
|
|
195
|
-
str = WebMock::Util::URI.strip_default_port_from_uri_string(@pattern.to_s)
|
|
196
|
-
str += " with query params #{@query_params.inspect}" if @query_params
|
|
197
|
-
str
|
|
246
|
+
def pattern_inspect
|
|
247
|
+
WebMock::Util::URI.strip_default_port_from_uri_string(@pattern.to_s)
|
|
198
248
|
end
|
|
199
249
|
end
|
|
200
250
|
|
|
@@ -232,8 +282,10 @@ module WebMock
|
|
|
232
282
|
|
|
233
283
|
if (@pattern).is_a?(Hash)
|
|
234
284
|
return true if @pattern.empty?
|
|
235
|
-
|
|
236
|
-
elsif (@pattern).is_a?(
|
|
285
|
+
matching_body_hashes?(body_as_hash(body, content_type), @pattern, content_type)
|
|
286
|
+
elsif (@pattern).is_a?(Array)
|
|
287
|
+
matching_body_array?(body_as_hash(body, content_type), @pattern, content_type)
|
|
288
|
+
elsif (@pattern).is_a?(WebMock::Matchers::HashArgumentMatcher)
|
|
237
289
|
@pattern == body_as_hash(body, content_type)
|
|
238
290
|
else
|
|
239
291
|
empty_string?(@pattern) && empty_string?(body) ||
|
|
@@ -247,8 +299,9 @@ module WebMock
|
|
|
247
299
|
end
|
|
248
300
|
|
|
249
301
|
private
|
|
302
|
+
|
|
250
303
|
def body_as_hash(body, content_type)
|
|
251
|
-
case
|
|
304
|
+
case body_format(content_type)
|
|
252
305
|
when :json then
|
|
253
306
|
WebMock::Util::JSON.parse(body)
|
|
254
307
|
when :xml then
|
|
@@ -258,6 +311,11 @@ module WebMock
|
|
|
258
311
|
end
|
|
259
312
|
end
|
|
260
313
|
|
|
314
|
+
def body_format(content_type)
|
|
315
|
+
normalized_content_type = content_type.sub(/\A(application\/)[a-zA-Z0-9.-]+\+(json|xml)\Z/,'\1\2')
|
|
316
|
+
BODY_FORMATS[normalized_content_type]
|
|
317
|
+
end
|
|
318
|
+
|
|
261
319
|
def assert_non_multipart_body(content_type)
|
|
262
320
|
if content_type =~ %r{^multipart/form-data}
|
|
263
321
|
raise ArgumentError.new("WebMock does not support matching body for multipart/form-data requests yet :(")
|
|
@@ -287,21 +345,36 @@ module WebMock
|
|
|
287
345
|
#
|
|
288
346
|
# @return [Boolean] true if the paramaters match the comparison
|
|
289
347
|
# hash, false if not.
|
|
290
|
-
def
|
|
348
|
+
def matching_body_hashes?(query_parameters, pattern, content_type)
|
|
291
349
|
return false unless query_parameters.is_a?(Hash)
|
|
292
350
|
return false unless query_parameters.keys.sort == pattern.keys.sort
|
|
293
|
-
|
|
351
|
+
|
|
352
|
+
query_parameters.all? do |key, actual|
|
|
294
353
|
expected = pattern[key]
|
|
354
|
+
matching_values(actual, expected, content_type)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
295
357
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
358
|
+
def matching_body_array?(query_parameters, pattern, content_type)
|
|
359
|
+
return false unless query_parameters.is_a?(Array)
|
|
360
|
+
return false unless query_parameters.length == pattern.length
|
|
361
|
+
|
|
362
|
+
query_parameters.each_with_index do |actual, index|
|
|
363
|
+
expected = pattern[index]
|
|
364
|
+
return false unless matching_values(actual, expected, content_type)
|
|
301
365
|
end
|
|
366
|
+
|
|
302
367
|
true
|
|
303
368
|
end
|
|
304
369
|
|
|
370
|
+
def matching_values(actual, expected, content_type)
|
|
371
|
+
return matching_body_hashes?(actual, expected, content_type) if actual.is_a?(Hash) && expected.is_a?(Hash)
|
|
372
|
+
return matching_body_array?(actual, expected, content_type) if actual.is_a?(Array) && expected.is_a?(Array)
|
|
373
|
+
|
|
374
|
+
expected = WebMock::Util::ValuesStringifier.stringify_values(expected) if url_encoded_body?(content_type)
|
|
375
|
+
expected === actual
|
|
376
|
+
end
|
|
377
|
+
|
|
305
378
|
def empty_string?(string)
|
|
306
379
|
string.nil? || string == ""
|
|
307
380
|
end
|
|
@@ -310,6 +383,9 @@ module WebMock
|
|
|
310
383
|
Hash[WebMock::Util::HashKeysStringifier.stringify_keys!(hash, deep: true).sort]
|
|
311
384
|
end
|
|
312
385
|
|
|
386
|
+
def url_encoded_body?(content_type)
|
|
387
|
+
content_type =~ %r{^application/x-www-form-urlencoded}
|
|
388
|
+
end
|
|
313
389
|
end
|
|
314
390
|
|
|
315
391
|
class HeadersPattern
|
|
@@ -333,6 +409,10 @@ module WebMock
|
|
|
333
409
|
WebMock::Util::Headers.sorted_headers_string(@pattern)
|
|
334
410
|
end
|
|
335
411
|
|
|
412
|
+
def pp_to_s
|
|
413
|
+
WebMock::Util::Headers.pp_headers_string(@pattern)
|
|
414
|
+
end
|
|
415
|
+
|
|
336
416
|
private
|
|
337
417
|
|
|
338
418
|
def empty_headers?(headers)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
|
|
3
5
|
class RequestRegistry
|
|
@@ -23,7 +25,7 @@ module WebMock
|
|
|
23
25
|
if requested_signatures.hash.empty?
|
|
24
26
|
"No requests were made."
|
|
25
27
|
else
|
|
26
|
-
text = ""
|
|
28
|
+
text = "".dup
|
|
27
29
|
self.requested_signatures.each do |request_signature, times_executed|
|
|
28
30
|
text << "#{request_signature} was made #{times_executed} time#{times_executed == 1 ? '' : 's' }\n"
|
|
29
31
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
|
|
3
5
|
class RequestSignature
|
|
@@ -12,7 +14,7 @@ module WebMock
|
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def to_s
|
|
15
|
-
string = "#{self.method.to_s.upcase}"
|
|
17
|
+
string = "#{self.method.to_s.upcase}".dup
|
|
16
18
|
string << " #{WebMock::Util::URI.strip_default_port_from_uri_string(self.uri.to_s)}"
|
|
17
19
|
string << " with body '#{body.to_s}'" if body && body.to_s != ''
|
|
18
20
|
if headers && !headers.empty?
|
|
@@ -35,11 +37,11 @@ module WebMock
|
|
|
35
37
|
alias == eql?
|
|
36
38
|
|
|
37
39
|
def url_encoded?
|
|
38
|
-
!!(headers
|
|
40
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/x-www-form-urlencoded'))
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def json_headers?
|
|
42
|
-
!!(headers
|
|
44
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/json'))
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
private
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "pp"
|
|
2
4
|
|
|
3
5
|
module WebMock
|
|
@@ -13,14 +15,14 @@ module WebMock
|
|
|
13
15
|
def stubbing_instructions
|
|
14
16
|
return unless WebMock.show_stubbing_instructions?
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
"You can stub this request with the following snippet:\n\n" +
|
|
19
|
+
WebMock::StubRequestSnippet.new(request_stub).to_s
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def request_stubs
|
|
21
23
|
return if WebMock::StubRegistry.instance.request_stubs.empty?
|
|
22
24
|
|
|
23
|
-
text = "registered request stubs:\n"
|
|
25
|
+
text = "registered request stubs:\n".dup
|
|
24
26
|
WebMock::StubRegistry.instance.request_stubs.each do |stub|
|
|
25
27
|
text << "\n#{WebMock::StubRequestSnippet.new(stub).to_s(false)}"
|
|
26
28
|
add_body_diff(stub, text) if WebMock.show_body_diff?
|
|
@@ -50,7 +52,7 @@ module WebMock
|
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
def pretty_print_to_string(string_to_print)
|
|
53
|
-
StringIO.open("") do |stream|
|
|
55
|
+
StringIO.open("".dup) do |stream|
|
|
54
56
|
PP.pp(string_to_print, stream)
|
|
55
57
|
stream.rewind
|
|
56
58
|
stream.read
|
data/lib/webmock/request_stub.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
class RequestStub
|
|
3
5
|
|
|
@@ -24,6 +26,38 @@ module WebMock
|
|
|
24
26
|
end
|
|
25
27
|
alias_method :and_return, :to_return
|
|
26
28
|
|
|
29
|
+
def to_return_json(*response_hashes)
|
|
30
|
+
raise ArgumentError, '#to_return_json does not support passing a block' if block_given?
|
|
31
|
+
|
|
32
|
+
json_response_hashes = [*response_hashes].flatten.map do |resp_h|
|
|
33
|
+
headers, body = resp_h.values_at(:headers, :body)
|
|
34
|
+
|
|
35
|
+
json_body = if body.respond_to?(:call)
|
|
36
|
+
->(request_signature) {
|
|
37
|
+
b = if body.respond_to?(:arity) && body.arity == 1
|
|
38
|
+
body.call(request_signature)
|
|
39
|
+
else
|
|
40
|
+
body.call
|
|
41
|
+
end
|
|
42
|
+
b = b.to_json unless b.is_a?(String)
|
|
43
|
+
b
|
|
44
|
+
}
|
|
45
|
+
elsif !body.is_a?(String)
|
|
46
|
+
body.to_json
|
|
47
|
+
else
|
|
48
|
+
body
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
resp_h.merge(
|
|
52
|
+
headers: {content_type: 'application/json'}.merge(headers.to_h),
|
|
53
|
+
body: json_body
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
to_return(json_response_hashes)
|
|
58
|
+
end
|
|
59
|
+
alias_method :and_return_json, :to_return_json
|
|
60
|
+
|
|
27
61
|
def to_rack(app, options={})
|
|
28
62
|
@responses_sequences << ResponsesSequence.new([RackResponse.new(app)])
|
|
29
63
|
end
|
data/lib/webmock/response.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "pathname"
|
|
2
4
|
|
|
3
5
|
module WebMock
|
|
@@ -14,8 +16,11 @@ module WebMock
|
|
|
14
16
|
|
|
15
17
|
class Response
|
|
16
18
|
def initialize(options = {})
|
|
17
|
-
|
|
19
|
+
case options
|
|
20
|
+
when IO, StringIO
|
|
18
21
|
self.options = read_raw_response(options)
|
|
22
|
+
when String
|
|
23
|
+
self.options = read_raw_response(StringIO.new(options))
|
|
19
24
|
else
|
|
20
25
|
self.options = options
|
|
21
26
|
end
|
|
@@ -33,7 +38,7 @@ module WebMock
|
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
def body
|
|
36
|
-
@body ||
|
|
41
|
+
@body || String.new("")
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
def body=(body)
|
|
@@ -91,10 +96,10 @@ module WebMock
|
|
|
91
96
|
|
|
92
97
|
def ==(other)
|
|
93
98
|
self.body == other.body &&
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
self.headers === other.headers &&
|
|
100
|
+
self.status == other.status &&
|
|
101
|
+
self.exception == other.exception &&
|
|
102
|
+
self.should_timeout == other.should_timeout
|
|
98
103
|
end
|
|
99
104
|
|
|
100
105
|
private
|
|
@@ -111,16 +116,17 @@ module WebMock
|
|
|
111
116
|
valid_types = [Proc, IO, Pathname, String, Array]
|
|
112
117
|
return if @body.nil?
|
|
113
118
|
return if valid_types.any? { |c| @body.is_a?(c) }
|
|
114
|
-
raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given"
|
|
115
|
-
end
|
|
116
119
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
if @body.class.is_a?(Hash)
|
|
121
|
+
raise InvalidBody, "must be one of: #{valid_types}, but you've used a #{@body.class}' instead." \
|
|
122
|
+
"\n What shall we encode it to? try calling .to_json .to_xml instead on the hash instead, or otherwise convert it to a string."
|
|
123
|
+
else
|
|
124
|
+
raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given"
|
|
122
125
|
end
|
|
123
|
-
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def read_raw_response(io)
|
|
129
|
+
socket = ::Net::BufferedIO.new(io)
|
|
124
130
|
response = ::Net::HTTPResponse.read_new(socket)
|
|
125
131
|
transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
|
|
126
132
|
response.reading_body(socket, true) {}
|
|
@@ -132,6 +138,8 @@ module WebMock
|
|
|
132
138
|
options[:body] = response.read_body
|
|
133
139
|
options[:status] = [response.code.to_i, response.message]
|
|
134
140
|
options
|
|
141
|
+
ensure
|
|
142
|
+
socket.close
|
|
135
143
|
end
|
|
136
144
|
|
|
137
145
|
InvalidBody = Class.new(StandardError)
|
data/lib/webmock/rspec.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'webmock'
|
|
2
4
|
|
|
3
5
|
# RSpec 1.x and 2.x compatibility
|
|
@@ -20,14 +22,21 @@ end
|
|
|
20
22
|
|
|
21
23
|
require 'webmock/rspec/matchers'
|
|
22
24
|
|
|
23
|
-
WebMock.enable!
|
|
24
|
-
|
|
25
25
|
RSPEC_CONFIGURER.configure { |config|
|
|
26
26
|
|
|
27
27
|
config.include WebMock::API
|
|
28
28
|
config.include WebMock::Matchers
|
|
29
29
|
|
|
30
|
-
config.
|
|
30
|
+
config.before(:suite) do
|
|
31
|
+
WebMock.enable!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
config.after(:suite) do
|
|
35
|
+
WebMock.disable!
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
config.around(:each) do |example|
|
|
39
|
+
example.run
|
|
31
40
|
WebMock.reset!
|
|
32
41
|
end
|
|
33
42
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module WebMock
|
|
2
4
|
|
|
3
5
|
class StubRegistry
|
|
@@ -10,25 +12,39 @@ module WebMock
|
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def global_stubs
|
|
13
|
-
@global_stubs ||= []
|
|
15
|
+
@global_stubs ||= Hash.new { |h, k| h[k] = [] }
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
def reset!
|
|
17
19
|
self.request_stubs = []
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
def register_global_stub(&block)
|
|
22
|
+
def register_global_stub(order = :before_local_stubs, &block)
|
|
23
|
+
unless %i[before_local_stubs after_local_stubs].include?(order)
|
|
24
|
+
raise ArgumentError.new("Wrong order. Use :before_local_stubs or :after_local_stubs")
|
|
25
|
+
end
|
|
26
|
+
|
|
21
27
|
# This hash contains the responses returned by the block,
|
|
22
28
|
# keyed by the exact request (using the object_id).
|
|
23
29
|
# That way, there's no race condition in case #to_return
|
|
24
30
|
# doesn't run immediately after stub.with.
|
|
25
31
|
responses = {}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
response_lock = Mutex.new
|
|
33
|
+
|
|
34
|
+
stub = ::WebMock::RequestStub.new(:any, ->(uri) { true }).with { |request|
|
|
35
|
+
update_response = -> { responses[request.object_id] = yield(request) }
|
|
36
|
+
|
|
37
|
+
# The block can recurse, so only lock if we don't already own it
|
|
38
|
+
if response_lock.owned?
|
|
39
|
+
update_response.call
|
|
40
|
+
else
|
|
41
|
+
response_lock.synchronize(&update_response)
|
|
42
|
+
end
|
|
43
|
+
}.to_return(lambda { |request|
|
|
44
|
+
response_lock.synchronize { responses.delete(request.object_id) }
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
global_stubs[order].push stub
|
|
32
48
|
end
|
|
33
49
|
|
|
34
50
|
def register_request_stub(stub)
|
|
@@ -54,9 +70,10 @@ module WebMock
|
|
|
54
70
|
private
|
|
55
71
|
|
|
56
72
|
def request_stub_for(request_signature)
|
|
57
|
-
(global_stubs + request_stubs
|
|
58
|
-
registered_request_stub
|
|
59
|
-
|
|
73
|
+
(global_stubs[:before_local_stubs] + request_stubs + global_stubs[:after_local_stubs])
|
|
74
|
+
.detect { |registered_request_stub|
|
|
75
|
+
registered_request_stub.request_pattern.matches?(request_signature)
|
|
76
|
+
}
|
|
60
77
|
end
|
|
61
78
|
|
|
62
79
|
def evaluate_response_for_request(response, request_signature)
|