webmock 3.14.0 → 3.19.1

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.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +124 -2
  3. data/README.md +46 -18
  4. data/lib/webmock/api.rb +2 -0
  5. data/lib/webmock/assertion_failure.rb +2 -0
  6. data/lib/webmock/callback_registry.rb +2 -0
  7. data/lib/webmock/config.rb +2 -0
  8. data/lib/webmock/cucumber.rb +2 -0
  9. data/lib/webmock/deprecation.rb +2 -0
  10. data/lib/webmock/errors.rb +2 -0
  11. data/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +8 -1
  12. data/lib/webmock/http_lib_adapters/curb_adapter.rb +4 -2
  13. data/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +14 -6
  14. data/lib/webmock/http_lib_adapters/excon_adapter.rb +2 -0
  15. data/lib/webmock/http_lib_adapters/http_lib_adapter.rb +2 -0
  16. data/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +2 -0
  17. data/lib/webmock/http_lib_adapters/http_rb/client.rb +3 -3
  18. data/lib/webmock/http_lib_adapters/http_rb/request.rb +3 -1
  19. data/lib/webmock/http_lib_adapters/http_rb/response.rb +6 -1
  20. data/lib/webmock/http_lib_adapters/http_rb/streamer.rb +6 -2
  21. data/lib/webmock/http_lib_adapters/http_rb/webmock.rb +8 -2
  22. data/lib/webmock/http_lib_adapters/http_rb_adapter.rb +2 -0
  23. data/lib/webmock/http_lib_adapters/httpclient_adapter.rb +2 -0
  24. data/lib/webmock/http_lib_adapters/manticore_adapter.rb +2 -0
  25. data/lib/webmock/http_lib_adapters/net_http.rb +24 -115
  26. data/lib/webmock/http_lib_adapters/net_http_response.rb +2 -0
  27. data/lib/webmock/http_lib_adapters/patron_adapter.rb +2 -0
  28. data/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +2 -0
  29. data/lib/webmock/matchers/any_arg_matcher.rb +2 -0
  30. data/lib/webmock/matchers/hash_argument_matcher.rb +2 -0
  31. data/lib/webmock/matchers/hash_excluding_matcher.rb +2 -0
  32. data/lib/webmock/matchers/hash_including_matcher.rb +2 -0
  33. data/lib/webmock/minitest.rb +2 -0
  34. data/lib/webmock/rack_response.rb +2 -0
  35. data/lib/webmock/request_body_diff.rb +2 -0
  36. data/lib/webmock/request_execution_verifier.rb +2 -0
  37. data/lib/webmock/request_pattern.rb +26 -8
  38. data/lib/webmock/request_registry.rb +2 -0
  39. data/lib/webmock/request_signature.rb +4 -2
  40. data/lib/webmock/request_signature_snippet.rb +2 -0
  41. data/lib/webmock/request_stub.rb +34 -0
  42. data/lib/webmock/response.rb +10 -8
  43. data/lib/webmock/responses_sequence.rb +2 -0
  44. data/lib/webmock/rspec/matchers/request_pattern_matcher.rb +2 -0
  45. data/lib/webmock/rspec/matchers/webmock_matcher.rb +2 -0
  46. data/lib/webmock/rspec/matchers.rb +2 -0
  47. data/lib/webmock/rspec.rb +2 -0
  48. data/lib/webmock/stub_registry.rb +2 -0
  49. data/lib/webmock/stub_request_snippet.rb +2 -0
  50. data/lib/webmock/test_unit.rb +2 -0
  51. data/lib/webmock/util/hash_counter.rb +12 -6
  52. data/lib/webmock/util/hash_keys_stringifier.rb +2 -0
  53. data/lib/webmock/util/hash_validator.rb +2 -0
  54. data/lib/webmock/util/headers.rb +22 -8
  55. data/lib/webmock/util/json.rb +2 -0
  56. data/lib/webmock/util/query_mapper.rb +2 -0
  57. data/lib/webmock/util/uri.rb +3 -1
  58. data/lib/webmock/util/values_stringifier.rb +2 -0
  59. data/lib/webmock/util/version_checker.rb +7 -5
  60. data/lib/webmock/version.rb +3 -1
  61. data/lib/webmock/webmock.rb +12 -0
  62. data/lib/webmock.rb +2 -0
  63. metadata +51 -183
  64. data/.gemtest +0 -0
  65. data/.github/workflows/CI.yml +0 -37
  66. data/.gitignore +0 -34
  67. data/.rspec-tm +0 -2
  68. data/Gemfile +0 -9
  69. data/Rakefile +0 -38
  70. data/minitest/test_helper.rb +0 -34
  71. data/minitest/test_webmock.rb +0 -9
  72. data/minitest/webmock_spec.rb +0 -60
  73. data/spec/acceptance/async_http_client/async_http_client_spec.rb +0 -375
  74. data/spec/acceptance/async_http_client/async_http_client_spec_helper.rb +0 -73
  75. data/spec/acceptance/curb/curb_spec.rb +0 -499
  76. data/spec/acceptance/curb/curb_spec_helper.rb +0 -147
  77. data/spec/acceptance/em_http_request/em_http_request_spec.rb +0 -462
  78. data/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +0 -77
  79. data/spec/acceptance/excon/excon_spec.rb +0 -77
  80. data/spec/acceptance/excon/excon_spec_helper.rb +0 -52
  81. data/spec/acceptance/http_rb/http_rb_spec.rb +0 -93
  82. data/spec/acceptance/http_rb/http_rb_spec_helper.rb +0 -54
  83. data/spec/acceptance/httpclient/httpclient_spec.rb +0 -217
  84. data/spec/acceptance/httpclient/httpclient_spec_helper.rb +0 -57
  85. data/spec/acceptance/manticore/manticore_spec.rb +0 -107
  86. data/spec/acceptance/manticore/manticore_spec_helper.rb +0 -35
  87. data/spec/acceptance/net_http/net_http_shared.rb +0 -153
  88. data/spec/acceptance/net_http/net_http_spec.rb +0 -369
  89. data/spec/acceptance/net_http/net_http_spec_helper.rb +0 -64
  90. data/spec/acceptance/net_http/real_net_http_spec.rb +0 -20
  91. data/spec/acceptance/patron/patron_spec.rb +0 -125
  92. data/spec/acceptance/patron/patron_spec_helper.rb +0 -54
  93. data/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +0 -313
  94. data/spec/acceptance/shared/callbacks.rb +0 -148
  95. data/spec/acceptance/shared/complex_cross_concern_behaviors.rb +0 -36
  96. data/spec/acceptance/shared/enabling_and_disabling_webmock.rb +0 -95
  97. data/spec/acceptance/shared/precedence_of_stubs.rb +0 -15
  98. data/spec/acceptance/shared/request_expectations.rb +0 -930
  99. data/spec/acceptance/shared/returning_declared_responses.rb +0 -409
  100. data/spec/acceptance/shared/stubbing_requests.rb +0 -678
  101. data/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +0 -135
  102. data/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +0 -60
  103. data/spec/acceptance/webmock_shared.rb +0 -41
  104. data/spec/fixtures/test.txt +0 -1
  105. data/spec/quality_spec.rb +0 -84
  106. data/spec/spec_helper.rb +0 -48
  107. data/spec/support/example_curl_output.txt +0 -22
  108. data/spec/support/failures.rb +0 -9
  109. data/spec/support/my_rack_app.rb +0 -53
  110. data/spec/support/network_connection.rb +0 -19
  111. data/spec/support/webmock_server.rb +0 -70
  112. data/spec/unit/api_spec.rb +0 -175
  113. data/spec/unit/errors_spec.rb +0 -129
  114. data/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +0 -17
  115. data/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +0 -12
  116. data/spec/unit/matchers/hash_excluding_matcher_spec.rb +0 -61
  117. data/spec/unit/matchers/hash_including_matcher_spec.rb +0 -87
  118. data/spec/unit/rack_response_spec.rb +0 -112
  119. data/spec/unit/request_body_diff_spec.rb +0 -90
  120. data/spec/unit/request_execution_verifier_spec.rb +0 -208
  121. data/spec/unit/request_pattern_spec.rb +0 -736
  122. data/spec/unit/request_registry_spec.rb +0 -95
  123. data/spec/unit/request_signature_snippet_spec.rb +0 -89
  124. data/spec/unit/request_signature_spec.rb +0 -155
  125. data/spec/unit/request_stub_spec.rb +0 -199
  126. data/spec/unit/response_spec.rb +0 -286
  127. data/spec/unit/stub_registry_spec.rb +0 -103
  128. data/spec/unit/stub_request_snippet_spec.rb +0 -115
  129. data/spec/unit/util/hash_counter_spec.rb +0 -39
  130. data/spec/unit/util/hash_keys_stringifier_spec.rb +0 -27
  131. data/spec/unit/util/headers_spec.rb +0 -28
  132. data/spec/unit/util/json_spec.rb +0 -33
  133. data/spec/unit/util/query_mapper_spec.rb +0 -157
  134. data/spec/unit/util/uri_spec.rb +0 -371
  135. data/spec/unit/util/version_checker_spec.rb +0 -65
  136. data/spec/unit/webmock_spec.rb +0 -60
  137. data/test/http_request.rb +0 -24
  138. data/test/shared_test.rb +0 -108
  139. data/test/test_helper.rb +0 -23
  140. data/test/test_webmock.rb +0 -12
  141. data/webmock.gemspec +0 -54
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'net/http'
2
4
  require 'net/https'
3
5
  require 'stringio'
@@ -10,24 +12,19 @@ module WebMock
10
12
  adapter_for :net_http
11
13
 
12
14
  OriginalNetHTTP = Net::HTTP unless const_defined?(:OriginalNetHTTP)
13
- OriginalNetBufferedIO = Net::BufferedIO unless const_defined?(:OriginalNetBufferedIO)
14
15
 
15
16
  def self.enable!
16
- Net.send(:remove_const, :BufferedIO)
17
17
  Net.send(:remove_const, :HTTP)
18
18
  Net.send(:remove_const, :HTTPSession)
19
19
  Net.send(:const_set, :HTTP, @webMockNetHTTP)
20
20
  Net.send(:const_set, :HTTPSession, @webMockNetHTTP)
21
- Net.send(:const_set, :BufferedIO, Net::WebMockNetBufferedIO)
22
21
  end
23
22
 
24
23
  def self.disable!
25
- Net.send(:remove_const, :BufferedIO)
26
24
  Net.send(:remove_const, :HTTP)
27
25
  Net.send(:remove_const, :HTTPSession)
28
26
  Net.send(:const_set, :HTTP, OriginalNetHTTP)
29
27
  Net.send(:const_set, :HTTPSession, OriginalNetHTTP)
30
- Net.send(:const_set, :BufferedIO, OriginalNetBufferedIO)
31
28
 
32
29
  #copy all constants from @webMockNetHTTP to original Net::HTTP
33
30
  #in case any constants were added to @webMockNetHTTP instead of Net::HTTP
@@ -98,13 +95,8 @@ module WebMock
98
95
  after_request.call(response)
99
96
  }
100
97
  if started?
101
- if WebMock::Config.instance.net_http_connect_on_start
102
- super_with_after_request.call
103
- else
104
- start_with_connect_without_finish {
105
- super_with_after_request.call
106
- }
107
- end
98
+ ensure_actual_connection
99
+ super_with_after_request.call
108
100
  else
109
101
  start_with_connect {
110
102
  super_with_after_request.call
@@ -119,32 +111,33 @@ module WebMock
119
111
  raise IOError, 'HTTP session already opened' if @started
120
112
  if block_given?
121
113
  begin
114
+ @socket = Net::HTTP.socket_type.new
122
115
  @started = true
123
116
  return yield(self)
124
117
  ensure
125
118
  do_finish
126
119
  end
127
120
  end
121
+ @socket = Net::HTTP.socket_type.new
128
122
  @started = true
129
123
  self
130
124
  end
131
125
 
132
126
 
133
- def start_with_connect_without_finish # :yield: http
134
- if block_given?
135
- begin
136
- do_start
137
- return yield(self)
138
- end
127
+ def ensure_actual_connection
128
+ if @socket.is_a?(StubSocket)
129
+ @socket&.close
130
+ @socket = nil
131
+ do_start
139
132
  end
140
- do_start
141
- self
142
133
  end
143
134
 
144
135
  alias_method :start_with_connect, :start
145
136
 
146
137
  def start(&block)
147
- if WebMock::Config.instance.net_http_connect_on_start
138
+ uri = Addressable::URI.parse(WebMock::NetHTTPUtility.get_uri(self))
139
+
140
+ if WebMock.net_http_connect_on_start?(uri)
148
141
  super(&block)
149
142
  else
150
143
  start_without_connect(&block)
@@ -169,7 +162,7 @@ module WebMock
169
162
  response.extend Net::WebMockHTTPResponse
170
163
 
171
164
  if webmock_response.should_timeout
172
- raise timeout_exception, "execution expired"
165
+ raise Net::OpenTimeout, "execution expired"
173
166
  end
174
167
 
175
168
  webmock_response.raise_error_if_any
@@ -179,16 +172,6 @@ module WebMock
179
172
  response
180
173
  end
181
174
 
182
- def timeout_exception
183
- if defined?(Net::OpenTimeout)
184
- # Ruby 2.x
185
- Net::OpenTimeout
186
- else
187
- # Fallback, if things change
188
- Timeout::Error
189
- end
190
- end
191
-
192
175
  def build_webmock_response(net_http_response)
193
176
  webmock_response = WebMock::Response.new
194
177
  webmock_response.status = [
@@ -222,31 +205,21 @@ module WebMock
222
205
  end
223
206
  end
224
207
 
225
- # patch for StringIO behavior in Ruby 2.2.3
226
- # https://github.com/bblimke/webmock/issues/558
227
- class PatchedStringIO < StringIO #:nodoc:
228
-
229
- alias_method :orig_read_nonblock, :read_nonblock
230
-
231
- def read_nonblock(size, *args, **kwargs)
232
- args.reject! {|arg| !arg.is_a?(Hash)}
233
- orig_read_nonblock(size, *args, **kwargs)
234
- end
235
-
236
- end
237
-
238
208
  class StubSocket #:nodoc:
239
209
 
240
210
  attr_accessor :read_timeout, :continue_timeout, :write_timeout
241
211
 
242
212
  def initialize(*args)
213
+ @closed = false
243
214
  end
244
215
 
245
216
  def closed?
246
- @closed ||= true
217
+ @closed
247
218
  end
248
219
 
249
220
  def close
221
+ @closed = true
222
+ nil
250
223
  end
251
224
 
252
225
  def readuntil(*args)
@@ -258,57 +231,13 @@ class StubSocket #:nodoc:
258
231
 
259
232
  class StubIO
260
233
  def setsockopt(*args); end
234
+ def peer_cert; end
235
+ def peeraddr; ["AF_INET", 443, "127.0.0.1", "127.0.0.1"] end
236
+ def ssl_version; "TLSv1.3" end
237
+ def cipher; ["TLS_AES_128_GCM_SHA256", "TLSv1.3", 128, 128] end
261
238
  end
262
239
  end
263
240
 
264
- module Net #:nodoc: all
265
-
266
- class WebMockNetBufferedIO < BufferedIO
267
- def initialize(io, *args, **kwargs)
268
- io = case io
269
- when Socket, OpenSSL::SSL::SSLSocket, IO
270
- io
271
- when StringIO
272
- PatchedStringIO.new(io.string)
273
- when String
274
- PatchedStringIO.new(io)
275
- end
276
- raise "Unable to create local socket" unless io
277
-
278
- # Prior to 2.4.0 `BufferedIO` only takes a single argument (`io`) with no
279
- # options. Here we pass through our full set of arguments only if we're
280
- # on 2.4.0 or later, and use a simplified invocation otherwise.
281
- if RUBY_VERSION >= '2.4.0'
282
- super
283
- else
284
- super(io)
285
- end
286
- end
287
-
288
- if RUBY_VERSION >= '2.6.0'
289
- # https://github.com/ruby/ruby/blob/7d02441f0d6e5c9d0a73a024519eba4f69e36dce/lib/net/protocol.rb#L208
290
- # Modified version of method from ruby, so that nil is always passed into orig_read_nonblock to avoid timeout
291
- def rbuf_fill
292
- case rv = @io.read_nonblock(BUFSIZE, nil, exception: false)
293
- when String
294
- return if rv.nil?
295
- @rbuf << rv
296
- rv.clear
297
- return
298
- when :wait_readable
299
- @io.to_io.wait_readable(@read_timeout) or raise Net::ReadTimeout
300
- when :wait_writable
301
- @io.to_io.wait_writable(@read_timeout) or raise Net::ReadTimeout
302
- when nil
303
- raise EOFError, 'end of file reached'
304
- end while true
305
- end
306
- end
307
- end
308
-
309
- end
310
-
311
-
312
241
  module WebMock
313
242
  module NetHTTPUtility
314
243
 
@@ -325,7 +254,6 @@ module WebMock
325
254
  method = request.method.downcase.to_sym
326
255
 
327
256
  headers = Hash[*request.to_hash.map {|k,v| [k, v]}.inject([]) {|r,x| r + x}]
328
- validate_headers(headers)
329
257
 
330
258
  if request.body_stream
331
259
  body = request.body_stream.read
@@ -341,7 +269,7 @@ module WebMock
341
269
  WebMock::RequestSignature.new(method, uri, body: request.body, headers: headers)
342
270
  end
343
271
 
344
- def self.get_uri(net_http, path)
272
+ def self.get_uri(net_http, path = nil)
345
273
  protocol = net_http.use_ssl? ? "https" : "http"
346
274
 
347
275
  hostname = net_http.address
@@ -350,25 +278,6 @@ module WebMock
350
278
  "#{protocol}://#{hostname}:#{net_http.port}#{path}"
351
279
  end
352
280
 
353
- def self.validate_headers(headers)
354
- # For Ruby versions < 2.3.0, if you make a request with headers that are symbols
355
- # Net::HTTP raises a NoMethodError
356
- #
357
- # WebMock normalizes headers when creating a RequestSignature,
358
- # and will update all headers from symbols to strings.
359
- #
360
- # This could create a false positive in a test suite with WebMock.
361
- #
362
- # So before this point, WebMock raises an ArgumentError if any of the headers are symbols
363
- # instead of the cryptic NoMethodError "undefined method `split' ...` from Net::HTTP
364
- if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.3.0')
365
- header_as_symbol = headers.keys.find {|header| header.is_a? Symbol}
366
- if header_as_symbol
367
- raise ArgumentError.new("Net:HTTP does not accept headers as symbols")
368
- end
369
- end
370
- end
371
-
372
281
  def self.check_right_http_connection
373
282
  @was_right_http_connection_loaded = defined?(RightHttpConnection)
374
283
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This code is entierly copied from VCR (http://github.com/myronmarston/vcr) by courtesy of Myron Marston
2
4
 
3
5
  # A Net::HTTP response that has already been read raises an IOError when #read_body
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'patron'
3
5
  rescue LoadError
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'typhoeus'
3
5
  rescue LoadError
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::AnyArgMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # Base class for Hash matchers
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::HashExcludingMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Matchers
3
5
  # this is a based on RSpec::Mocks::ArgumentMatchers::HashIncludingMatcher
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'minitest/test'
3
5
  test_class = Minitest::Test
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class RackResponse < Response
3
5
  def initialize(app)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "hashdiff"
2
4
  require "json"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class RequestExecutionVerifier
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
 
3
5
  module RSpecMatcherDetector
@@ -281,7 +283,9 @@ module WebMock
281
283
  if (@pattern).is_a?(Hash)
282
284
  return true if @pattern.empty?
283
285
  matching_body_hashes?(body_as_hash(body, content_type), @pattern, content_type)
284
- elsif (@pattern).is_a?(WebMock::Matchers::HashIncludingMatcher)
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)
285
289
  @pattern == body_as_hash(body, content_type)
286
290
  else
287
291
  empty_string?(@pattern) && empty_string?(body) ||
@@ -344,19 +348,33 @@ module WebMock
344
348
  def matching_body_hashes?(query_parameters, pattern, content_type)
345
349
  return false unless query_parameters.is_a?(Hash)
346
350
  return false unless query_parameters.keys.sort == pattern.keys.sort
347
- query_parameters.each do |key, actual|
351
+
352
+ query_parameters.all? do |key, actual|
348
353
  expected = pattern[key]
354
+ matching_values(actual, expected, content_type)
355
+ end
356
+ end
349
357
 
350
- if actual.is_a?(Hash) && expected.is_a?(Hash)
351
- return false unless matching_body_hashes?(actual, expected, content_type)
352
- else
353
- expected = WebMock::Util::ValuesStringifier.stringify_values(expected) if url_encoded_body?(content_type)
354
- return false unless expected === actual
355
- end
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)
356
365
  end
366
+
357
367
  true
358
368
  end
359
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
+
360
378
  def empty_string?(string)
361
379
  string.nil? || string == ""
362
380
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
 
3
5
  class RequestRegistry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
 
3
5
  class RequestSignature
@@ -35,11 +37,11 @@ module WebMock
35
37
  alias == eql?
36
38
 
37
39
  def url_encoded?
38
- !!(headers && headers['Content-Type'] == 'application/x-www-form-urlencoded')
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 && headers['Content-Type'] == 'application/json')
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
@@ -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
@@ -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
- if options.is_a?(IO) || options.is_a?(String)
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
@@ -120,13 +125,8 @@ module WebMock
120
125
  end
121
126
  end
122
127
 
123
- def read_raw_response(raw_response)
124
- if raw_response.is_a?(IO)
125
- string = raw_response.read
126
- raw_response.close
127
- raw_response = string
128
- end
129
- socket = ::Net::BufferedIO.new(raw_response)
128
+ def read_raw_response(io)
129
+ socket = ::Net::BufferedIO.new(io)
130
130
  response = ::Net::HTTPResponse.read_new(socket)
131
131
  transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
132
132
  response.reading_body(socket, true) {}
@@ -138,6 +138,8 @@ module WebMock
138
138
  options[:body] = response.read_body
139
139
  options[:status] = [response.code.to_i, response.message]
140
140
  options
141
+ ensure
142
+ socket.close
141
143
  end
142
144
 
143
145
  InvalidBody = Class.new(StandardError)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
 
3
5
  class ResponsesSequence
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class RequestPatternMatcher
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class WebMockMatcher
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'webmock'
2
4
  require 'webmock/rspec/matchers/request_pattern_matcher'
3
5
  require 'webmock/rspec/matchers/webmock_matcher'
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
 
3
5
  class StubRegistry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class StubRequestSnippet
3
5
  def initialize(request_stub)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test/unit'
2
4
  require 'webmock'
3
5
 
@@ -1,29 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thread'
2
4
 
3
5
  module WebMock
4
6
  module Util
5
7
  class HashCounter
6
8
  attr_accessor :hash
9
+
7
10
  def initialize
8
- self.hash = {}
11
+ self.hash = Hash.new(0)
9
12
  @order = {}
10
13
  @max = 0
11
14
  @lock = ::Mutex.new
12
15
  end
13
- def put key, num=1
16
+
17
+ def put(key, num=1)
14
18
  @lock.synchronize do
15
- hash[key] = (hash[key] || 0) + num
16
- @order[key] = @max = @max + 1
19
+ hash[key] += num
20
+ @order[key] = @max += 1
17
21
  end
18
22
  end
19
- def get key
23
+
24
+ def get(key)
20
25
  @lock.synchronize do
21
- hash[key] || 0
26
+ hash[key]
22
27
  end
23
28
  end
24
29
 
25
30
  def select(&block)
26
31
  return unless block_given?
32
+
27
33
  @lock.synchronize do
28
34
  hash.select(&block)
29
35
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  module Util
3
5
  class HashKeysStringifier
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module WebMock
2
4
  class HashValidator
3
5
  def initialize(hash)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'base64'
2
4
 
3
5
  module WebMock
@@ -6,18 +8,21 @@ module WebMock
6
8
 
7
9
  class Headers
8
10
 
11
+ STANDARD_HEADER_DELIMITER = '-'.freeze
12
+ NONSTANDARD_HEADER_DELIMITER = '_'.freeze
13
+ JOIN = ', '.freeze
14
+
9
15
  def self.normalize_headers(headers)
10
16
  return nil unless headers
11
- array = headers.map { |name, value|
12
- [name.to_s.split(/_|-/).map { |segment| segment.capitalize }.join("-"),
13
- case value
17
+
18
+ headers.each_with_object({}) do |(name, value), new_headers|
19
+ new_headers[normalize_name(name)] =
20
+ case value
14
21
  when Regexp then value
15
- when Array then (value.size == 1) ? value.first.to_s : value.map {|v| v.to_s}.sort
22
+ when Array then (value.size == 1) ? value.first.to_s : value.map(&:to_s).sort
16
23
  else value.to_s
17
- end
18
- ]
19
- }
20
- Hash[*array.inject([]) {|r,x| r + x}]
24
+ end
25
+ end
21
26
  end
22
27
 
23
28
  def self.sorted_headers_string(headers)
@@ -57,6 +62,15 @@ module WebMock
57
62
  "Basic #{Base64.strict_encode64(credentials.join(':')).chomp}"
58
63
  end
59
64
 
65
+ def self.normalize_name(name)
66
+ name
67
+ .to_s
68
+ .tr(NONSTANDARD_HEADER_DELIMITER, STANDARD_HEADER_DELIMITER)
69
+ .split(STANDARD_HEADER_DELIMITER)
70
+ .map!(&:capitalize)
71
+ .join(STANDARD_HEADER_DELIMITER)
72
+ end
73
+
60
74
  end
61
75
 
62
76
  end