webmock 3.14.0 → 3.19.1

Sign up to get free protection for your applications and to get access to all the features.
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