ultra-pure-gem 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.
- checksums.yaml +7 -0
- data/ultra-pure-gem.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 +61 -0
- metadata +106 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
class RequestStub
|
|
5
|
+
|
|
6
|
+
attr_accessor :request_pattern
|
|
7
|
+
|
|
8
|
+
def initialize(method, uri)
|
|
9
|
+
@request_pattern = RequestPattern.new(method, uri)
|
|
10
|
+
@responses_sequences = []
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def with(params = {}, &block)
|
|
15
|
+
@request_pattern.with(params, &block)
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_return(*response_hashes, &block)
|
|
20
|
+
if block
|
|
21
|
+
@responses_sequences << ResponsesSequence.new([ResponseFactory.response_for(block)])
|
|
22
|
+
else
|
|
23
|
+
@responses_sequences << ResponsesSequence.new([*response_hashes].flatten.map {|r| ResponseFactory.response_for(r)})
|
|
24
|
+
end
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
alias_method :and_return, :to_return
|
|
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
|
+
|
|
61
|
+
def to_rack(app, options={})
|
|
62
|
+
@responses_sequences << ResponsesSequence.new([RackResponse.new(app)])
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def to_raise(*exceptions)
|
|
66
|
+
@responses_sequences << ResponsesSequence.new([*exceptions].flatten.map {|e|
|
|
67
|
+
ResponseFactory.response_for(exception: e)
|
|
68
|
+
})
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
alias_method :and_raise, :to_raise
|
|
72
|
+
|
|
73
|
+
def to_timeout
|
|
74
|
+
@responses_sequences << ResponsesSequence.new([ResponseFactory.response_for(should_timeout: true)])
|
|
75
|
+
self
|
|
76
|
+
end
|
|
77
|
+
alias_method :and_timeout, :to_timeout
|
|
78
|
+
|
|
79
|
+
def response
|
|
80
|
+
if @responses_sequences.empty?
|
|
81
|
+
WebMock::Response.new
|
|
82
|
+
elsif @responses_sequences.length > 1
|
|
83
|
+
@responses_sequences.shift if @responses_sequences.first.end?
|
|
84
|
+
@responses_sequences.first.next_response
|
|
85
|
+
else
|
|
86
|
+
@responses_sequences[0].next_response
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def has_responses?
|
|
91
|
+
!@responses_sequences.empty?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def then
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def times(number)
|
|
99
|
+
raise "times(N) accepts integers >= 1 only" if !number.is_a?(Integer) || number < 1
|
|
100
|
+
if @responses_sequences.empty?
|
|
101
|
+
raise "Invalid WebMock stub declaration." +
|
|
102
|
+
" times(N) can be declared only after response declaration."
|
|
103
|
+
end
|
|
104
|
+
@responses_sequences.last.times_to_repeat += number-1
|
|
105
|
+
self
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def matches?(request_signature)
|
|
109
|
+
self.request_pattern.matches?(request_signature)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def to_s
|
|
113
|
+
self.request_pattern.to_s
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def self.from_request_signature(signature)
|
|
117
|
+
stub = self.new(signature.method.to_sym, signature.uri.to_s)
|
|
118
|
+
|
|
119
|
+
if signature.body.to_s != ''
|
|
120
|
+
body = if signature.url_encoded?
|
|
121
|
+
WebMock::Util::QueryMapper.query_to_values(signature.body, notation: Config.instance.query_values_notation)
|
|
122
|
+
else
|
|
123
|
+
signature.body
|
|
124
|
+
end
|
|
125
|
+
stub.with(body: body)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if (signature.headers && !signature.headers.empty?)
|
|
129
|
+
stub.with(headers: signature.headers)
|
|
130
|
+
end
|
|
131
|
+
stub
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
|
|
5
|
+
module WebMock
|
|
6
|
+
|
|
7
|
+
class ResponseFactory
|
|
8
|
+
def self.response_for(options)
|
|
9
|
+
if options.respond_to?(:call)
|
|
10
|
+
WebMock::DynamicResponse.new(options)
|
|
11
|
+
else
|
|
12
|
+
WebMock::Response.new(options)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Response
|
|
18
|
+
def initialize(options = {})
|
|
19
|
+
case options
|
|
20
|
+
when IO, StringIO
|
|
21
|
+
self.options = read_raw_response(options)
|
|
22
|
+
when String
|
|
23
|
+
self.options = read_raw_response(StringIO.new(options))
|
|
24
|
+
else
|
|
25
|
+
self.options = options
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def headers
|
|
30
|
+
@headers
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def headers=(headers)
|
|
34
|
+
@headers = headers
|
|
35
|
+
if @headers && !@headers.is_a?(Proc)
|
|
36
|
+
@headers = Util::Headers.normalize_headers(@headers)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def body
|
|
41
|
+
@body || String.new("")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def body=(body)
|
|
45
|
+
@body = body
|
|
46
|
+
assert_valid_body!
|
|
47
|
+
stringify_body!
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def status
|
|
51
|
+
@status || [200, ""]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def status=(status)
|
|
55
|
+
@status = status.is_a?(Integer) ? [status, ""] : status
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def exception
|
|
59
|
+
@exception
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def exception=(exception)
|
|
63
|
+
@exception = case exception
|
|
64
|
+
when String then StandardError.new(exception)
|
|
65
|
+
when Class then exception.new('Exception from WebMock')
|
|
66
|
+
when Exception then exception
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def raise_error_if_any
|
|
71
|
+
raise @exception if @exception
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def should_timeout
|
|
75
|
+
@should_timeout == true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def options=(options)
|
|
79
|
+
options = WebMock::Util::HashKeysStringifier.stringify_keys!(options)
|
|
80
|
+
HashValidator.new(options).validate_keys('headers', 'status', 'body', 'exception', 'should_timeout')
|
|
81
|
+
self.headers = options['headers']
|
|
82
|
+
self.status = options['status']
|
|
83
|
+
self.body = options['body']
|
|
84
|
+
self.exception = options['exception']
|
|
85
|
+
@should_timeout = options['should_timeout']
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def evaluate(request_signature)
|
|
89
|
+
self.body = @body.call(request_signature) if @body.is_a?(Proc)
|
|
90
|
+
self.headers = @headers.call(request_signature) if @headers.is_a?(Proc)
|
|
91
|
+
self.status = @status.call(request_signature) if @status.is_a?(Proc)
|
|
92
|
+
@should_timeout = @should_timeout.call(request_signature) if @should_timeout.is_a?(Proc)
|
|
93
|
+
@exception = @exception.call(request_signature) if @exception.is_a?(Proc)
|
|
94
|
+
self
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def ==(other)
|
|
98
|
+
self.body == other.body &&
|
|
99
|
+
self.headers === other.headers &&
|
|
100
|
+
self.status == other.status &&
|
|
101
|
+
self.exception == other.exception &&
|
|
102
|
+
self.should_timeout == other.should_timeout
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
def stringify_body!
|
|
108
|
+
if @body.is_a?(IO) || @body.is_a?(Pathname)
|
|
109
|
+
io = @body
|
|
110
|
+
@body = io.read
|
|
111
|
+
io.close if io.respond_to?(:close)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def assert_valid_body!
|
|
116
|
+
valid_types = [Proc, IO, Pathname, String, Array]
|
|
117
|
+
return if @body.nil?
|
|
118
|
+
return if valid_types.any? { |c| @body.is_a?(c) }
|
|
119
|
+
|
|
120
|
+
if @body.is_a?(Hash)
|
|
121
|
+
raise InvalidBody, "must be one of: #{valid_types}, but you've used a #{@body.class}. " \
|
|
122
|
+
"Please convert it by calling .to_json .to_xml, or otherwise convert it to a string."
|
|
123
|
+
else
|
|
124
|
+
raise InvalidBody, "must be one of: #{valid_types}. '#{@body.class}' given."
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def read_raw_response(io)
|
|
129
|
+
socket = ::Net::BufferedIO.new(io)
|
|
130
|
+
response = ::Net::HTTPResponse.read_new(socket)
|
|
131
|
+
transfer_encoding = response.delete('transfer-encoding') #chunks were already read by curl
|
|
132
|
+
response.reading_body(socket, true) {}
|
|
133
|
+
|
|
134
|
+
options = {}
|
|
135
|
+
options[:headers] = {}
|
|
136
|
+
response.each_header {|name, value| options[:headers][name] = value}
|
|
137
|
+
options[:headers]['transfer-encoding'] = transfer_encoding if transfer_encoding
|
|
138
|
+
options[:body] = response.read_body
|
|
139
|
+
options[:status] = [response.code.to_i, response.message]
|
|
140
|
+
options
|
|
141
|
+
ensure
|
|
142
|
+
socket.close
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
InvalidBody = Class.new(StandardError)
|
|
146
|
+
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
class DynamicResponse < Response
|
|
150
|
+
attr_accessor :responder
|
|
151
|
+
|
|
152
|
+
def initialize(responder)
|
|
153
|
+
@responder = responder
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def evaluate(request_signature)
|
|
157
|
+
options = @responder.call(request_signature)
|
|
158
|
+
Response.new(options)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
|
|
5
|
+
class ResponsesSequence
|
|
6
|
+
|
|
7
|
+
attr_accessor :times_to_repeat
|
|
8
|
+
|
|
9
|
+
def initialize(responses)
|
|
10
|
+
@times_to_repeat = 1
|
|
11
|
+
@responses = responses
|
|
12
|
+
@current_position = 0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def end?
|
|
16
|
+
@times_to_repeat == 0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def next_response
|
|
20
|
+
if @times_to_repeat > 0
|
|
21
|
+
response = @responses[@current_position]
|
|
22
|
+
increase_position
|
|
23
|
+
response
|
|
24
|
+
else
|
|
25
|
+
@responses.last
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def increase_position
|
|
32
|
+
if @current_position == (@responses.length - 1)
|
|
33
|
+
@current_position = 0
|
|
34
|
+
@times_to_repeat -= 1
|
|
35
|
+
else
|
|
36
|
+
@current_position += 1
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
class RequestPatternMatcher
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@request_execution_verifier = RequestExecutionVerifier.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def once
|
|
11
|
+
@request_execution_verifier.expected_times_executed = 1
|
|
12
|
+
self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def twice
|
|
16
|
+
@request_execution_verifier.expected_times_executed = 2
|
|
17
|
+
self
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def times(times)
|
|
21
|
+
@request_execution_verifier.expected_times_executed = times.to_i
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def at_least_once
|
|
26
|
+
@request_execution_verifier.at_least_times_executed = 1
|
|
27
|
+
self
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def at_least_twice
|
|
31
|
+
@request_execution_verifier.at_least_times_executed = 2
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def at_least_times(times)
|
|
36
|
+
@request_execution_verifier.at_least_times_executed = times.to_i
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def at_most_once
|
|
41
|
+
@request_execution_verifier.at_most_times_executed = 1
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def at_most_twice
|
|
46
|
+
@request_execution_verifier.at_most_times_executed = 2
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def at_most_times(times)
|
|
51
|
+
@request_execution_verifier.at_most_times_executed = times.to_i
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def matches?(request_pattern)
|
|
56
|
+
@request_execution_verifier.request_pattern = request_pattern
|
|
57
|
+
@request_execution_verifier.matches?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def does_not_match?(request_pattern)
|
|
61
|
+
@request_execution_verifier.request_pattern = request_pattern
|
|
62
|
+
@request_execution_verifier.does_not_match?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def failure_message
|
|
66
|
+
@request_execution_verifier.failure_message
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def failure_message_when_negated
|
|
70
|
+
@request_execution_verifier.failure_message_when_negated
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def description
|
|
74
|
+
@request_execution_verifier.description
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# RSpec 2 compatibility:
|
|
78
|
+
alias_method :negative_failure_message, :failure_message_when_negated
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
class WebMockMatcher
|
|
5
|
+
|
|
6
|
+
def initialize(method, uri)
|
|
7
|
+
@request_execution_verifier = RequestExecutionVerifier.new
|
|
8
|
+
@request_execution_verifier.request_pattern = RequestPattern.new(method, uri)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def once
|
|
12
|
+
@request_execution_verifier.expected_times_executed = 1
|
|
13
|
+
self
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def twice
|
|
17
|
+
@request_execution_verifier.expected_times_executed = 2
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def at_least_once
|
|
22
|
+
@request_execution_verifier.at_least_times_executed = 1
|
|
23
|
+
self
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def at_least_twice
|
|
27
|
+
@request_execution_verifier.at_least_times_executed = 2
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def at_least_times(times)
|
|
32
|
+
@request_execution_verifier.at_least_times_executed = times
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def with(options = {}, &block)
|
|
37
|
+
@request_execution_verifier.request_pattern.with(options, &block)
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def times(times)
|
|
42
|
+
@request_execution_verifier.expected_times_executed = times.to_i
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def matches?(webmock)
|
|
47
|
+
@request_execution_verifier.matches?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def does_not_match?(webmock)
|
|
51
|
+
@request_execution_verifier.does_not_match?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def failure_message
|
|
55
|
+
@request_execution_verifier.failure_message
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def failure_message_when_negated
|
|
59
|
+
@request_execution_verifier.failure_message_when_negated
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def description
|
|
63
|
+
@request_execution_verifier.description
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# RSpec 2 compatibility:
|
|
67
|
+
alias_method :negative_failure_message, :failure_message_when_negated
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'webmock'
|
|
4
|
+
require 'webmock/rspec/matchers/request_pattern_matcher'
|
|
5
|
+
require 'webmock/rspec/matchers/webmock_matcher'
|
|
6
|
+
|
|
7
|
+
module WebMock
|
|
8
|
+
module Matchers
|
|
9
|
+
def have_been_made
|
|
10
|
+
WebMock::RequestPatternMatcher.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def have_been_requested
|
|
14
|
+
WebMock::RequestPatternMatcher.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def have_not_been_made
|
|
18
|
+
WebMock::RequestPatternMatcher.new.times(0)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def have_requested(method, uri)
|
|
22
|
+
WebMock::WebMockMatcher.new(method, uri)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def have_not_requested(method, uri)
|
|
26
|
+
WebMock::WebMockMatcher.new(method, uri).times(0)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'webmock'
|
|
4
|
+
|
|
5
|
+
# RSpec 1.x and 2.x compatibility
|
|
6
|
+
if defined?(RSpec::Expectations::ExpectationNotMetError)
|
|
7
|
+
RSPEC_NAMESPACE = RSPEC_CONFIGURER = RSpec
|
|
8
|
+
elsif defined?(Spec) && defined?(Spec.configure)
|
|
9
|
+
RSPEC_NAMESPACE = Spec
|
|
10
|
+
RSPEC_CONFIGURER = Spec::Runner
|
|
11
|
+
else
|
|
12
|
+
begin
|
|
13
|
+
require 'rspec/core'
|
|
14
|
+
require 'rspec/expectations'
|
|
15
|
+
RSPEC_NAMESPACE = RSPEC_CONFIGURER = RSpec
|
|
16
|
+
rescue LoadError
|
|
17
|
+
require 'spec'
|
|
18
|
+
RSPEC_NAMESPACE = Spec
|
|
19
|
+
RSPEC_CONFIGURER = Spec::Runner
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require 'webmock/rspec/matchers'
|
|
24
|
+
|
|
25
|
+
RSPEC_CONFIGURER.configure { |config|
|
|
26
|
+
|
|
27
|
+
config.include WebMock::API
|
|
28
|
+
config.include WebMock::Matchers
|
|
29
|
+
|
|
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
|
|
40
|
+
WebMock.reset!
|
|
41
|
+
end
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
WebMock::AssertionFailure.error_class = RSPEC_NAMESPACE::Expectations::ExpectationNotMetError
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
|
|
5
|
+
class StubRegistry
|
|
6
|
+
include Singleton
|
|
7
|
+
|
|
8
|
+
attr_accessor :request_stubs
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
reset!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def global_stubs
|
|
15
|
+
@global_stubs ||= Hash.new { |h, k| h[k] = [] }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def reset!
|
|
19
|
+
self.request_stubs = []
|
|
20
|
+
end
|
|
21
|
+
|
|
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
|
+
|
|
27
|
+
# This hash contains the responses returned by the block,
|
|
28
|
+
# keyed by the exact request (using the object_id).
|
|
29
|
+
# That way, there's no race condition in case #to_return
|
|
30
|
+
# doesn't run immediately after stub.with.
|
|
31
|
+
responses = {}
|
|
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
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def register_request_stub(stub)
|
|
51
|
+
request_stubs.insert(0, stub)
|
|
52
|
+
stub
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def remove_request_stub(stub)
|
|
56
|
+
if not request_stubs.delete(stub)
|
|
57
|
+
raise "Request stub \n\n #{stub.to_s} \n\n is not registered."
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def registered_request?(request_signature)
|
|
62
|
+
request_stub_for(request_signature)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def response_for_request(request_signature)
|
|
66
|
+
stub = request_stub_for(request_signature)
|
|
67
|
+
stub ? evaluate_response_for_request(stub.response, request_signature) : nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def request_stub_for(request_signature)
|
|
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
|
+
}
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def evaluate_response_for_request(response, request_signature)
|
|
80
|
+
response.dup.evaluate(request_signature)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebMock
|
|
4
|
+
class StubRequestSnippet
|
|
5
|
+
def initialize(request_stub)
|
|
6
|
+
@request_stub = request_stub
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def body_pattern
|
|
10
|
+
request_pattern.body_pattern
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s(with_response = true)
|
|
14
|
+
request_pattern = @request_stub.request_pattern
|
|
15
|
+
string = "stub_request(:#{request_pattern.method_pattern.to_s},".dup
|
|
16
|
+
string << " \"#{request_pattern.uri_pattern.to_s}\")"
|
|
17
|
+
|
|
18
|
+
with = "".dup
|
|
19
|
+
|
|
20
|
+
if (request_pattern.body_pattern)
|
|
21
|
+
with << "\n body: #{request_pattern.body_pattern.to_s}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if (request_pattern.headers_pattern)
|
|
25
|
+
with << "," unless with.empty?
|
|
26
|
+
|
|
27
|
+
with << "\n headers: #{request_pattern.headers_pattern.pp_to_s}"
|
|
28
|
+
end
|
|
29
|
+
string << ".\n with(#{with})" unless with.empty?
|
|
30
|
+
if with_response
|
|
31
|
+
if request_pattern.headers_pattern && request_pattern.headers_pattern.matches?({ 'Accept' => "application/json" })
|
|
32
|
+
string << ".\n to_return(status: 200, body: \"{}\", headers: {})"
|
|
33
|
+
else
|
|
34
|
+
string << ".\n to_return(status: 200, body: \"\", headers: {})"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
string
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'webmock'
|
|
5
|
+
|
|
6
|
+
WebMock.enable!
|
|
7
|
+
|
|
8
|
+
module Test
|
|
9
|
+
module Unit
|
|
10
|
+
class TestCase
|
|
11
|
+
include WebMock::API
|
|
12
|
+
|
|
13
|
+
teardown
|
|
14
|
+
def teardown_with_webmock
|
|
15
|
+
WebMock.reset!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
WebMock::AssertionFailure.error_class = Test::Unit::AssertionFailedError
|