ultra-safe-box 0.0.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.
Potentially problematic release.
This version of ultra-safe-box might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/ultra-safe-box.gemspec +12 -0
- data/webmock-3.26.2/CHANGELOG.md +2148 -0
- data/webmock-3.26.2/LICENSE +20 -0
- data/webmock-3.26.2/README.md +1229 -0
- data/webmock-3.26.2/lib/webmock/api.rb +111 -0
- data/webmock-3.26.2/lib/webmock/assertion_failure.rb +13 -0
- data/webmock-3.26.2/lib/webmock/callback_registry.rb +37 -0
- data/webmock-3.26.2/lib/webmock/config.rb +20 -0
- data/webmock-3.26.2/lib/webmock/cucumber.rb +12 -0
- data/webmock-3.26.2/lib/webmock/deprecation.rb +11 -0
- data/webmock-3.26.2/lib/webmock/errors.rb +19 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/async_http_client_adapter.rb +228 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/curb_adapter.rb +354 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +239 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/excon_adapter.rb +167 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter.rb +9 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +21 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/client.rb +17 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/request.rb +28 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/response.rb +95 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/streamer.rb +44 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb/webmock.rb +77 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/http_rb_adapter.rb +39 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/httpclient_adapter.rb +260 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/manticore_adapter.rb +147 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http.rb +310 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/net_http_response.rb +36 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/patron_adapter.rb +132 -0
- data/webmock-3.26.2/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +190 -0
- data/webmock-3.26.2/lib/webmock/matchers/any_arg_matcher.rb +15 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_argument_matcher.rb +23 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_excluding_matcher.rb +17 -0
- data/webmock-3.26.2/lib/webmock/matchers/hash_including_matcher.rb +19 -0
- data/webmock-3.26.2/lib/webmock/minitest.rb +43 -0
- data/webmock-3.26.2/lib/webmock/rack_response.rb +73 -0
- data/webmock-3.26.2/lib/webmock/request_body_diff.rb +66 -0
- data/webmock-3.26.2/lib/webmock/request_execution_verifier.rb +79 -0
- data/webmock-3.26.2/lib/webmock/request_pattern.rb +428 -0
- data/webmock-3.26.2/lib/webmock/request_registry.rb +37 -0
- data/webmock-3.26.2/lib/webmock/request_signature.rb +56 -0
- data/webmock-3.26.2/lib/webmock/request_signature_snippet.rb +63 -0
- data/webmock-3.26.2/lib/webmock/request_stub.rb +134 -0
- data/webmock-3.26.2/lib/webmock/response.rb +161 -0
- data/webmock-3.26.2/lib/webmock/responses_sequence.rb +42 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers/request_pattern_matcher.rb +80 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers/webmock_matcher.rb +69 -0
- data/webmock-3.26.2/lib/webmock/rspec/matchers.rb +29 -0
- data/webmock-3.26.2/lib/webmock/rspec.rb +44 -0
- data/webmock-3.26.2/lib/webmock/stub_registry.rb +84 -0
- data/webmock-3.26.2/lib/webmock/stub_request_snippet.rb +40 -0
- data/webmock-3.26.2/lib/webmock/test_unit.rb +22 -0
- data/webmock-3.26.2/lib/webmock/util/hash_counter.rb +45 -0
- data/webmock-3.26.2/lib/webmock/util/hash_keys_stringifier.rb +27 -0
- data/webmock-3.26.2/lib/webmock/util/hash_validator.rb +19 -0
- data/webmock-3.26.2/lib/webmock/util/headers.rb +77 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/json.rb +72 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/parse_error.rb +7 -0
- data/webmock-3.26.2/lib/webmock/util/parsers/xml.rb +16 -0
- data/webmock-3.26.2/lib/webmock/util/query_mapper.rb +283 -0
- data/webmock-3.26.2/lib/webmock/util/uri.rb +113 -0
- data/webmock-3.26.2/lib/webmock/util/values_stringifier.rb +22 -0
- data/webmock-3.26.2/lib/webmock/util/version_checker.rb +113 -0
- data/webmock-3.26.2/lib/webmock/version.rb +5 -0
- data/webmock-3.26.2/lib/webmock/webmock.rb +175 -0
- data/webmock-3.26.2/lib/webmock.rb +209 -0
- metadata +106 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
|
|
5
|
+
module RSpecMatcherDetector
|
|
6
|
+
def rSpecHashIncludingMatcher?(matcher)
|
|
7
|
+
matcher.class.name =~ /R?Spec::Mocks::ArgumentMatchers::HashIncludingMatcher/
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def rSpecHashExcludingMatcher?(matcher)
|
|
11
|
+
matcher.class.name =~ /R?Spec::Mocks::ArgumentMatchers::HashExcludingMatcher/
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class RequestPattern
|
|
16
|
+
|
|
17
|
+
attr_reader :method_pattern, :uri_pattern, :body_pattern, :headers_pattern
|
|
18
|
+
|
|
19
|
+
def initialize(method, uri, options = {})
|
|
20
|
+
@method_pattern = MethodPattern.new(method)
|
|
21
|
+
@uri_pattern = create_uri_pattern(uri)
|
|
22
|
+
@body_pattern = nil
|
|
23
|
+
@headers_pattern = nil
|
|
24
|
+
@with_block = nil
|
|
25
|
+
assign_options(options)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def with(options = {}, &block)
|
|
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?
|
|
30
|
+
assign_options(options)
|
|
31
|
+
@with_block = block
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def matches?(request_signature)
|
|
36
|
+
content_type = request_signature.headers['Content-Type'] if request_signature.headers
|
|
37
|
+
content_type = content_type.split(';').first if content_type
|
|
38
|
+
@method_pattern.matches?(request_signature.method) &&
|
|
39
|
+
@uri_pattern.matches?(request_signature.uri) &&
|
|
40
|
+
(@body_pattern.nil? || @body_pattern.matches?(request_signature.body, content_type || "")) &&
|
|
41
|
+
(@headers_pattern.nil? || @headers_pattern.matches?(request_signature.headers)) &&
|
|
42
|
+
(@with_block.nil? || @with_block.call(request_signature))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_s
|
|
46
|
+
string = "#{@method_pattern.to_s.upcase}".dup
|
|
47
|
+
string << " #{@uri_pattern.to_s}"
|
|
48
|
+
string << " with body #{@body_pattern.to_s}" if @body_pattern
|
|
49
|
+
string << " with headers #{@headers_pattern.to_s}" if @headers_pattern
|
|
50
|
+
string << " with given block" if @with_block
|
|
51
|
+
string
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def assign_options(options)
|
|
58
|
+
options = WebMock::Util::HashKeysStringifier.stringify_keys!(options, deep: true)
|
|
59
|
+
HashValidator.new(options).validate_keys('body', 'headers', 'query', 'basic_auth')
|
|
60
|
+
set_basic_auth_as_headers!(options)
|
|
61
|
+
@body_pattern = BodyPattern.new(options['body']) if options.has_key?('body')
|
|
62
|
+
@headers_pattern = HeadersPattern.new(options['headers']) if options.has_key?('headers')
|
|
63
|
+
@uri_pattern.add_query_params(options['query']) if options.has_key?('query')
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def set_basic_auth_as_headers!(options)
|
|
67
|
+
if basic_auth = options.delete('basic_auth')
|
|
68
|
+
validate_basic_auth!(basic_auth)
|
|
69
|
+
options['headers'] ||= {}
|
|
70
|
+
options['headers']['Authorization'] = WebMock::Util::Headers.basic_auth_header(basic_auth[0],basic_auth[1])
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def validate_basic_auth!(basic_auth)
|
|
75
|
+
if !basic_auth.is_a?(Array) || basic_auth.map{|e| e.is_a?(String)}.uniq != [true]
|
|
76
|
+
raise "The basic_auth option value should be an array which contains 2 strings: username and password"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def create_uri_pattern(uri)
|
|
81
|
+
if uri.is_a?(Regexp)
|
|
82
|
+
URIRegexpPattern.new(uri)
|
|
83
|
+
elsif uri.is_a?(Addressable::Template)
|
|
84
|
+
URIAddressablePattern.new(uri)
|
|
85
|
+
elsif uri.respond_to?(:call)
|
|
86
|
+
URICallablePattern.new(uri)
|
|
87
|
+
elsif uri.is_a?(::URI::Generic)
|
|
88
|
+
URIStringPattern.new(uri.to_s)
|
|
89
|
+
elsif uri.respond_to?(:to_str)
|
|
90
|
+
URIStringPattern.new(uri.to_str)
|
|
91
|
+
else
|
|
92
|
+
raise ArgumentError.new("URI should be a String, Regexp, Addressable::Template, a callable object, or respond to #to_str. Got: #{uri.class}")
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class MethodPattern
|
|
99
|
+
def initialize(pattern)
|
|
100
|
+
@pattern = pattern
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def matches?(method)
|
|
104
|
+
@pattern == method || @pattern == :any
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def to_s
|
|
108
|
+
@pattern.to_s
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class URIPattern
|
|
114
|
+
include RSpecMatcherDetector
|
|
115
|
+
|
|
116
|
+
def initialize(pattern)
|
|
117
|
+
@pattern = if pattern.is_a?(Addressable::URI) \
|
|
118
|
+
|| pattern.is_a?(Addressable::Template)
|
|
119
|
+
pattern
|
|
120
|
+
elsif pattern.respond_to?(:call)
|
|
121
|
+
pattern
|
|
122
|
+
else
|
|
123
|
+
WebMock::Util::URI.normalize_uri(pattern)
|
|
124
|
+
end
|
|
125
|
+
@query_params = nil
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def add_query_params(query_params)
|
|
129
|
+
@query_params = if query_params.is_a?(Hash)
|
|
130
|
+
query_params
|
|
131
|
+
elsif query_params.is_a?(WebMock::Matchers::HashIncludingMatcher) \
|
|
132
|
+
|| query_params.is_a?(WebMock::Matchers::HashExcludingMatcher)
|
|
133
|
+
query_params
|
|
134
|
+
elsif rSpecHashIncludingMatcher?(query_params)
|
|
135
|
+
WebMock::Matchers::HashIncludingMatcher.from_rspec_matcher(query_params)
|
|
136
|
+
elsif rSpecHashExcludingMatcher?(query_params)
|
|
137
|
+
WebMock::Matchers::HashExcludingMatcher.from_rspec_matcher(query_params)
|
|
138
|
+
else
|
|
139
|
+
WebMock::Util::QueryMapper.query_to_values(query_params, notation: Config.instance.query_values_notation)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def matches?(uri)
|
|
144
|
+
pattern_matches?(uri) && query_params_matches?(uri)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def to_s
|
|
148
|
+
str = pattern_inspect
|
|
149
|
+
str += " with query params #{@query_params.inspect}" if @query_params
|
|
150
|
+
str
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
def pattern_inspect
|
|
156
|
+
@pattern.inspect
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def query_params_matches?(uri)
|
|
160
|
+
@query_params.nil? || @query_params == WebMock::Util::QueryMapper.query_to_values(uri.query, notation: Config.instance.query_values_notation)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
class URICallablePattern < URIPattern
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def pattern_matches?(uri)
|
|
168
|
+
@pattern.call(uri)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
class URIRegexpPattern < URIPattern
|
|
173
|
+
private
|
|
174
|
+
|
|
175
|
+
def pattern_matches?(uri)
|
|
176
|
+
WebMock::Util::URI.variations_of_uri_as_strings(uri).any? { |u| u.match(@pattern) }
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
class URIAddressablePattern < URIPattern
|
|
181
|
+
def add_query_params(query_params)
|
|
182
|
+
@@add_query_params_warned ||= false
|
|
183
|
+
if not @@add_query_params_warned
|
|
184
|
+
@@add_query_params_warned = true
|
|
185
|
+
warn "WebMock warning: ignoring query params in RFC 6570 template and checking them with WebMock"
|
|
186
|
+
end
|
|
187
|
+
super(query_params)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
private
|
|
191
|
+
|
|
192
|
+
def pattern_matches?(uri)
|
|
193
|
+
if @query_params.nil?
|
|
194
|
+
# Let Addressable check the whole URI
|
|
195
|
+
matches_with_variations?(uri)
|
|
196
|
+
else
|
|
197
|
+
# WebMock checks the query, Addressable checks everything else
|
|
198
|
+
matches_with_variations?(uri.omit(:query))
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def pattern_inspect
|
|
203
|
+
@pattern.pattern.inspect
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def matches_with_variations?(uri)
|
|
207
|
+
template =
|
|
208
|
+
begin
|
|
209
|
+
Addressable::Template.new(WebMock::Util::URI.heuristic_parse(@pattern.pattern))
|
|
210
|
+
rescue Addressable::URI::InvalidURIError
|
|
211
|
+
Addressable::Template.new(@pattern.pattern)
|
|
212
|
+
end
|
|
213
|
+
WebMock::Util::URI.variations_of_uri_as_strings(uri).any? { |u|
|
|
214
|
+
template_matches_uri?(template, u)
|
|
215
|
+
}
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def template_matches_uri?(template, uri)
|
|
219
|
+
template.match(uri)
|
|
220
|
+
rescue Addressable::URI::InvalidURIError
|
|
221
|
+
false
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
class URIStringPattern < URIPattern
|
|
226
|
+
def add_query_params(query_params)
|
|
227
|
+
super
|
|
228
|
+
if @query_params.is_a?(Hash) || @query_params.is_a?(String)
|
|
229
|
+
query_hash = (WebMock::Util::QueryMapper.query_to_values(@pattern.query, notation: Config.instance.query_values_notation) || {}).merge(@query_params)
|
|
230
|
+
@pattern.query = WebMock::Util::QueryMapper.values_to_query(query_hash, notation: WebMock::Config.instance.query_values_notation)
|
|
231
|
+
@query_params = nil
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
private
|
|
236
|
+
|
|
237
|
+
def pattern_matches?(uri)
|
|
238
|
+
if @pattern.is_a?(Addressable::URI)
|
|
239
|
+
if @query_params
|
|
240
|
+
uri.omit(:query) === @pattern
|
|
241
|
+
else
|
|
242
|
+
uri === @pattern
|
|
243
|
+
end
|
|
244
|
+
else
|
|
245
|
+
false
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def pattern_inspect
|
|
250
|
+
WebMock::Util::URI.strip_default_port_from_uri_string(@pattern.to_s)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class BodyPattern
|
|
256
|
+
include RSpecMatcherDetector
|
|
257
|
+
|
|
258
|
+
BODY_FORMATS = {
|
|
259
|
+
'text/xml' => :xml,
|
|
260
|
+
'application/xml' => :xml,
|
|
261
|
+
'application/json' => :json,
|
|
262
|
+
'text/json' => :json,
|
|
263
|
+
'application/javascript' => :json,
|
|
264
|
+
'text/javascript' => :json,
|
|
265
|
+
'text/html' => :html,
|
|
266
|
+
'application/x-yaml' => :yaml,
|
|
267
|
+
'text/yaml' => :yaml,
|
|
268
|
+
'text/plain' => :plain
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
attr_reader :pattern
|
|
272
|
+
|
|
273
|
+
def initialize(pattern)
|
|
274
|
+
@pattern = if pattern.is_a?(Hash)
|
|
275
|
+
normalize_hash(pattern)
|
|
276
|
+
elsif rSpecHashIncludingMatcher?(pattern)
|
|
277
|
+
WebMock::Matchers::HashIncludingMatcher.from_rspec_matcher(pattern)
|
|
278
|
+
else
|
|
279
|
+
pattern
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def matches?(body, content_type = "")
|
|
284
|
+
assert_non_multipart_body(content_type)
|
|
285
|
+
|
|
286
|
+
if (@pattern).is_a?(Hash)
|
|
287
|
+
return true if @pattern.empty?
|
|
288
|
+
matching_body_hashes?(body_as_hash(body, content_type), @pattern, content_type)
|
|
289
|
+
elsif (@pattern).is_a?(Array)
|
|
290
|
+
matching_body_array?(body_as_hash(body, content_type), @pattern, content_type)
|
|
291
|
+
elsif (@pattern).is_a?(WebMock::Matchers::HashArgumentMatcher)
|
|
292
|
+
@pattern == body_as_hash(body, content_type)
|
|
293
|
+
else
|
|
294
|
+
empty_string?(@pattern) && empty_string?(body) ||
|
|
295
|
+
@pattern == body ||
|
|
296
|
+
@pattern === body
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def to_s
|
|
301
|
+
@pattern.inspect
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
private
|
|
305
|
+
|
|
306
|
+
def body_as_hash(body, content_type)
|
|
307
|
+
case body_format(content_type)
|
|
308
|
+
when :json then
|
|
309
|
+
WebMock::Util::Parsers::JSON.parse(body)
|
|
310
|
+
when :xml then
|
|
311
|
+
WebMock::Util::Parsers::XML.parse(body)
|
|
312
|
+
else
|
|
313
|
+
WebMock::Util::QueryMapper.query_to_values(body, notation: Config.instance.query_values_notation)
|
|
314
|
+
end
|
|
315
|
+
rescue WebMock::Util::Parsers::ParseError
|
|
316
|
+
nil
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def body_format(content_type)
|
|
320
|
+
normalized_content_type = content_type.sub(/\A(application\/)[a-zA-Z0-9.-]+\+(json|xml)\Z/,'\1\2')
|
|
321
|
+
BODY_FORMATS[normalized_content_type]
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def assert_non_multipart_body(content_type)
|
|
325
|
+
if content_type =~ %r{^multipart/form-data}
|
|
326
|
+
raise ArgumentError.new("WebMock does not support matching body for multipart/form-data requests yet :(")
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Compare two hashes for equality
|
|
331
|
+
#
|
|
332
|
+
# For two hashes to match they must have the same length and all
|
|
333
|
+
# values must match when compared using `#===`.
|
|
334
|
+
#
|
|
335
|
+
# The following hashes are examples of matches:
|
|
336
|
+
#
|
|
337
|
+
# {a: /\d+/} and {a: '123'}
|
|
338
|
+
#
|
|
339
|
+
# {a: '123'} and {a: '123'}
|
|
340
|
+
#
|
|
341
|
+
# {a: {b: /\d+/}} and {a: {b: '123'}}
|
|
342
|
+
#
|
|
343
|
+
# {a: {b: 'wow'}} and {a: {b: 'wow'}}
|
|
344
|
+
#
|
|
345
|
+
# @param [Hash] query_parameters typically the result of parsing
|
|
346
|
+
# JSON, XML or URL encoded parameters.
|
|
347
|
+
#
|
|
348
|
+
# @param [Hash] pattern which contains keys with a string, hash or
|
|
349
|
+
# regular expression value to use for comparison.
|
|
350
|
+
#
|
|
351
|
+
# @return [Boolean] true if the paramaters match the comparison
|
|
352
|
+
# hash, false if not.
|
|
353
|
+
def matching_body_hashes?(query_parameters, pattern, content_type)
|
|
354
|
+
return false unless query_parameters.is_a?(Hash)
|
|
355
|
+
return false unless query_parameters.keys.sort == pattern.keys.sort
|
|
356
|
+
|
|
357
|
+
query_parameters.all? do |key, actual|
|
|
358
|
+
expected = pattern[key]
|
|
359
|
+
matching_values(actual, expected, content_type)
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def matching_body_array?(query_parameters, pattern, content_type)
|
|
364
|
+
return false unless query_parameters.is_a?(Array)
|
|
365
|
+
return false unless query_parameters.length == pattern.length
|
|
366
|
+
|
|
367
|
+
query_parameters.each_with_index do |actual, index|
|
|
368
|
+
expected = pattern[index]
|
|
369
|
+
return false unless matching_values(actual, expected, content_type)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
true
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def matching_values(actual, expected, content_type)
|
|
376
|
+
return matching_body_hashes?(actual, expected, content_type) if actual.is_a?(Hash) && expected.is_a?(Hash)
|
|
377
|
+
return matching_body_array?(actual, expected, content_type) if actual.is_a?(Array) && expected.is_a?(Array)
|
|
378
|
+
|
|
379
|
+
expected = WebMock::Util::ValuesStringifier.stringify_values(expected) if url_encoded_body?(content_type)
|
|
380
|
+
expected === actual
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def empty_string?(string)
|
|
384
|
+
string.nil? || string == ""
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def normalize_hash(hash)
|
|
388
|
+
Hash[WebMock::Util::HashKeysStringifier.stringify_keys!(hash, deep: true).sort]
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def url_encoded_body?(content_type)
|
|
392
|
+
content_type =~ %r{^application/x-www-form-urlencoded}
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
class HeadersPattern
|
|
397
|
+
def initialize(pattern)
|
|
398
|
+
@pattern = WebMock::Util::Headers.normalize_headers(pattern) || {}
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def matches?(headers)
|
|
402
|
+
if empty_headers?(@pattern)
|
|
403
|
+
empty_headers?(headers)
|
|
404
|
+
else
|
|
405
|
+
return false if empty_headers?(headers)
|
|
406
|
+
@pattern.each do |key, value|
|
|
407
|
+
return false unless headers.has_key?(key) && value === headers[key]
|
|
408
|
+
end
|
|
409
|
+
true
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def to_s
|
|
414
|
+
WebMock::Util::Headers.sorted_headers_string(@pattern)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def pp_to_s
|
|
418
|
+
WebMock::Util::Headers.pp_headers_string(@pattern)
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
private
|
|
422
|
+
|
|
423
|
+
def empty_headers?(headers)
|
|
424
|
+
headers.nil? || headers == {}
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
|
|
5
|
+
class RequestRegistry
|
|
6
|
+
include Singleton
|
|
7
|
+
|
|
8
|
+
attr_accessor :requested_signatures
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
reset!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def reset!
|
|
15
|
+
self.requested_signatures = Util::HashCounter.new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def times_executed(request_pattern)
|
|
19
|
+
self.requested_signatures.select do |request_signature|
|
|
20
|
+
request_pattern.matches?(request_signature)
|
|
21
|
+
end.inject(0) { |sum, (_, times_executed)| sum + times_executed }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_s
|
|
25
|
+
if requested_signatures.hash.empty?
|
|
26
|
+
"No requests were made."
|
|
27
|
+
else
|
|
28
|
+
text = "".dup
|
|
29
|
+
self.requested_signatures.each do |request_signature, times_executed|
|
|
30
|
+
text << "#{request_signature} was made #{times_executed} time#{times_executed == 1 ? '' : 's' }\n"
|
|
31
|
+
end
|
|
32
|
+
text
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
|
|
5
|
+
class RequestSignature
|
|
6
|
+
|
|
7
|
+
attr_accessor :method, :uri, :body
|
|
8
|
+
attr_reader :headers
|
|
9
|
+
|
|
10
|
+
def initialize(method, uri, options = {})
|
|
11
|
+
self.method = method.to_sym
|
|
12
|
+
self.uri = uri.is_a?(Addressable::URI) ? uri : WebMock::Util::URI.normalize_uri(uri)
|
|
13
|
+
assign_options(options)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_s
|
|
17
|
+
string = "#{self.method.to_s.upcase}".dup
|
|
18
|
+
string << " #{WebMock::Util::URI.strip_default_port_from_uri_string(self.uri.to_s)}"
|
|
19
|
+
string << " with body '#{body.to_s}'" if body && body.to_s != ''
|
|
20
|
+
if headers && !headers.empty?
|
|
21
|
+
string << " with headers #{WebMock::Util::Headers.sorted_headers_string(headers)}"
|
|
22
|
+
end
|
|
23
|
+
string
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def headers=(headers)
|
|
27
|
+
@headers = WebMock::Util::Headers.normalize_headers(headers)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def hash
|
|
31
|
+
self.to_s.hash
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def eql?(other)
|
|
35
|
+
self.to_s == other.to_s
|
|
36
|
+
end
|
|
37
|
+
alias == eql?
|
|
38
|
+
|
|
39
|
+
def url_encoded?
|
|
40
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/x-www-form-urlencoded'))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def json_headers?
|
|
44
|
+
!!(headers&.fetch('Content-Type', nil)&.start_with?('application/json'))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def assign_options(options)
|
|
50
|
+
self.body = options[:body] if options.has_key?(:body)
|
|
51
|
+
self.headers = options[:headers] if options.has_key?(:headers)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pp"
|
|
4
|
+
|
|
5
|
+
module WebMock
|
|
6
|
+
class RequestSignatureSnippet
|
|
7
|
+
|
|
8
|
+
attr_reader :request_signature, :request_stub
|
|
9
|
+
|
|
10
|
+
def initialize(request_signature)
|
|
11
|
+
@request_signature = request_signature
|
|
12
|
+
@request_stub = RequestStub.from_request_signature(request_signature)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def stubbing_instructions
|
|
16
|
+
return unless WebMock.show_stubbing_instructions?
|
|
17
|
+
|
|
18
|
+
"You can stub this request with the following snippet:\n\n" +
|
|
19
|
+
WebMock::StubRequestSnippet.new(request_stub).to_s
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def request_stubs
|
|
23
|
+
return if WebMock::StubRegistry.instance.request_stubs.empty?
|
|
24
|
+
|
|
25
|
+
text = "registered request stubs:\n".dup
|
|
26
|
+
WebMock::StubRegistry.instance.request_stubs.each do |stub|
|
|
27
|
+
text << "\n#{WebMock::StubRequestSnippet.new(stub).to_s(false)}"
|
|
28
|
+
add_body_diff(stub, text) if WebMock.show_body_diff?
|
|
29
|
+
end
|
|
30
|
+
text
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def add_body_diff(stub, text)
|
|
36
|
+
body_diff_str = signature_stub_body_diff(stub)
|
|
37
|
+
text << "\n\n#{body_diff_str}" unless body_diff_str.empty?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def signature_stub_body_diff(stub)
|
|
41
|
+
diff = RequestBodyDiff.new(request_signature, stub).body_diff
|
|
42
|
+
diff.empty? ? "" : "Body diff:\n #{pretty_print_to_string(diff)}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def request_params
|
|
46
|
+
@request_params ||=
|
|
47
|
+
if request_signature.json_headers?
|
|
48
|
+
JSON.parse(request_signature.body)
|
|
49
|
+
else
|
|
50
|
+
""
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def pretty_print_to_string(string_to_print)
|
|
55
|
+
StringIO.open("".dup) do |stream|
|
|
56
|
+
PP.pp(string_to_print, stream)
|
|
57
|
+
stream.rewind
|
|
58
|
+
stream.read
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end
|