faraday 0.17.6 → 1.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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +52 -8
  3. data/LICENSE.md +1 -1
  4. data/README.md +18 -358
  5. data/Rakefile +1 -7
  6. data/examples/client_spec.rb +65 -0
  7. data/examples/client_test.rb +79 -0
  8. data/lib/faraday/adapter/em_http.rb +142 -99
  9. data/lib/faraday/adapter/em_http_ssl_patch.rb +24 -18
  10. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +18 -15
  11. data/lib/faraday/adapter/em_synchrony.rb +104 -60
  12. data/lib/faraday/adapter/excon.rb +98 -56
  13. data/lib/faraday/adapter/httpclient.rb +83 -59
  14. data/lib/faraday/adapter/net_http.rb +129 -63
  15. data/lib/faraday/adapter/net_http_persistent.rb +50 -27
  16. data/lib/faraday/adapter/patron.rb +80 -43
  17. data/lib/faraday/adapter/rack.rb +30 -13
  18. data/lib/faraday/adapter/test.rb +86 -53
  19. data/lib/faraday/adapter/typhoeus.rb +4 -1
  20. data/lib/faraday/adapter.rb +82 -22
  21. data/lib/faraday/adapter_registry.rb +30 -0
  22. data/lib/faraday/autoload.rb +47 -36
  23. data/lib/faraday/connection.rb +312 -182
  24. data/lib/faraday/dependency_loader.rb +37 -0
  25. data/lib/faraday/encoders/flat_params_encoder.rb +98 -0
  26. data/lib/faraday/encoders/nested_params_encoder.rb +171 -0
  27. data/lib/faraday/error.rb +9 -35
  28. data/lib/faraday/file_part.rb +128 -0
  29. data/lib/faraday/logging/formatter.rb +105 -0
  30. data/lib/faraday/middleware.rb +12 -28
  31. data/lib/faraday/middleware_registry.rb +129 -0
  32. data/lib/faraday/options/connection_options.rb +22 -0
  33. data/lib/faraday/options/env.rb +181 -0
  34. data/lib/faraday/options/proxy_options.rb +28 -0
  35. data/lib/faraday/options/request_options.rb +22 -0
  36. data/lib/faraday/options/ssl_options.rb +59 -0
  37. data/lib/faraday/options.rb +32 -183
  38. data/lib/faraday/param_part.rb +53 -0
  39. data/lib/faraday/parameters.rb +4 -197
  40. data/lib/faraday/rack_builder.rb +66 -55
  41. data/lib/faraday/request/authorization.rb +44 -30
  42. data/lib/faraday/request/basic_authentication.rb +14 -7
  43. data/lib/faraday/request/instrumentation.rb +45 -27
  44. data/lib/faraday/request/multipart.rb +79 -48
  45. data/lib/faraday/request/retry.rb +197 -171
  46. data/lib/faraday/request/token_authentication.rb +15 -10
  47. data/lib/faraday/request/url_encoded.rb +43 -23
  48. data/lib/faraday/request.rb +68 -38
  49. data/lib/faraday/response/logger.rb +22 -69
  50. data/lib/faraday/response/raise_error.rb +38 -18
  51. data/lib/faraday/response.rb +24 -14
  52. data/lib/faraday/utils/headers.rb +139 -0
  53. data/lib/faraday/utils/params_hash.rb +61 -0
  54. data/lib/faraday/utils.rb +36 -245
  55. data/lib/faraday.rb +94 -175
  56. data/spec/external_adapters/faraday_specs_setup.rb +14 -0
  57. data/spec/faraday/adapter/em_http_spec.rb +47 -0
  58. data/spec/faraday/adapter/em_synchrony_spec.rb +16 -0
  59. data/spec/faraday/adapter/excon_spec.rb +49 -0
  60. data/spec/faraday/adapter/httpclient_spec.rb +73 -0
  61. data/spec/faraday/adapter/net_http_persistent_spec.rb +57 -0
  62. data/spec/faraday/adapter/net_http_spec.rb +64 -0
  63. data/spec/faraday/adapter/patron_spec.rb +18 -0
  64. data/spec/faraday/adapter/rack_spec.rb +8 -0
  65. data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
  66. data/spec/faraday/adapter_registry_spec.rb +28 -0
  67. data/spec/faraday/adapter_spec.rb +55 -0
  68. data/spec/faraday/composite_read_io_spec.rb +80 -0
  69. data/spec/faraday/connection_spec.rb +691 -0
  70. data/spec/faraday/error_spec.rb +0 -57
  71. data/spec/faraday/middleware_spec.rb +26 -0
  72. data/spec/faraday/options/env_spec.rb +70 -0
  73. data/spec/faraday/options/options_spec.rb +297 -0
  74. data/spec/faraday/options/proxy_options_spec.rb +37 -0
  75. data/spec/faraday/options/request_options_spec.rb +19 -0
  76. data/spec/faraday/params_encoders/flat_spec.rb +34 -0
  77. data/spec/faraday/params_encoders/nested_spec.rb +134 -0
  78. data/spec/faraday/rack_builder_spec.rb +196 -0
  79. data/spec/faraday/request/authorization_spec.rb +88 -0
  80. data/spec/faraday/request/instrumentation_spec.rb +76 -0
  81. data/spec/faraday/request/multipart_spec.rb +274 -0
  82. data/spec/faraday/request/retry_spec.rb +242 -0
  83. data/spec/faraday/request/url_encoded_spec.rb +83 -0
  84. data/spec/faraday/request_spec.rb +109 -0
  85. data/spec/faraday/response/logger_spec.rb +220 -0
  86. data/spec/faraday/response/middleware_spec.rb +68 -0
  87. data/spec/faraday/response/raise_error_spec.rb +15 -15
  88. data/spec/faraday/response_spec.rb +75 -0
  89. data/spec/faraday/utils/headers_spec.rb +82 -0
  90. data/spec/faraday/utils_spec.rb +56 -0
  91. data/spec/faraday_spec.rb +37 -0
  92. data/spec/spec_helper.rb +63 -36
  93. data/spec/support/disabling_stub.rb +14 -0
  94. data/spec/support/fake_safe_buffer.rb +15 -0
  95. data/spec/support/helper_methods.rb +133 -0
  96. data/spec/support/shared_examples/adapter.rb +104 -0
  97. data/spec/support/shared_examples/params_encoder.rb +18 -0
  98. data/spec/support/shared_examples/request_method.rb +234 -0
  99. data/spec/support/streaming_response_checker.rb +35 -0
  100. data/spec/support/webmock_rack_app.rb +68 -0
  101. metadata +66 -38
  102. data/lib/faraday/deprecate.rb +0 -109
  103. data/lib/faraday/upload_io.rb +0 -77
  104. data/spec/faraday/deprecate_spec.rb +0 -147
  105. data/test/adapters/default_test.rb +0 -14
  106. data/test/adapters/em_http_test.rb +0 -30
  107. data/test/adapters/em_synchrony_test.rb +0 -32
  108. data/test/adapters/excon_test.rb +0 -30
  109. data/test/adapters/httpclient_test.rb +0 -34
  110. data/test/adapters/integration.rb +0 -263
  111. data/test/adapters/logger_test.rb +0 -136
  112. data/test/adapters/net_http_persistent_test.rb +0 -114
  113. data/test/adapters/net_http_test.rb +0 -79
  114. data/test/adapters/patron_test.rb +0 -40
  115. data/test/adapters/rack_test.rb +0 -38
  116. data/test/adapters/test_middleware_test.rb +0 -157
  117. data/test/adapters/typhoeus_test.rb +0 -38
  118. data/test/authentication_middleware_test.rb +0 -65
  119. data/test/composite_read_io_test.rb +0 -109
  120. data/test/connection_test.rb +0 -738
  121. data/test/env_test.rb +0 -268
  122. data/test/helper.rb +0 -75
  123. data/test/live_server.rb +0 -67
  124. data/test/middleware/instrumentation_test.rb +0 -88
  125. data/test/middleware/retry_test.rb +0 -282
  126. data/test/middleware_stack_test.rb +0 -260
  127. data/test/multibyte.txt +0 -1
  128. data/test/options_test.rb +0 -333
  129. data/test/parameters_test.rb +0 -157
  130. data/test/request_middleware_test.rb +0 -126
  131. data/test/response_middleware_test.rb +0 -72
  132. data/test/strawberry.rb +0 -2
  133. data/test/utils_test.rb +0 -98
@@ -41,62 +41,5 @@ RSpec.describe Faraday::ClientError do
41
41
  it { expect(subject.message).to eq('["error1", "error2"]') }
42
42
  it { expect(subject.inspect).to eq('#<Faraday::ClientError #<Faraday::ClientError: ["error1", "error2"]>>') }
43
43
  end
44
-
45
- context 'maintains backward-compatibility until 1.0' do
46
- it 'does not raise an error for error-namespaced classes but prints an error message' do
47
- error_message, error = with_warn_squelching { Faraday::Error::ClientError.new('foo') }
48
-
49
- expect(error).to be_a Faraday::ClientError
50
- expect(error_message).to match(
51
- Regexp.new(
52
- 'NOTE: Faraday::Error::ClientError.new is deprecated; '\
53
- 'use Faraday::ClientError.new instead. It will be removed in or after version 1.0'
54
- )
55
- )
56
- end
57
-
58
- it 'does not raise an error for inherited error-namespaced classes but prints an error message' do
59
- error_message, = with_warn_squelching { Class.new(Faraday::Error::ClientError) }
60
-
61
- expect(error_message).to match(
62
- Regexp.new(
63
- 'NOTE: Inheriting Faraday::Error::ClientError is deprecated; '\
64
- 'use Faraday::ClientError instead. It will be removed in or after version 1.0'
65
- )
66
- )
67
- end
68
-
69
- it 'allows backward-compatible class to be subclassed' do
70
- expect {
71
- with_warn_squelching { Class.new(Faraday::Error::ClientError) }
72
- }.not_to raise_error
73
- end
74
-
75
- it 'allows rescuing of a current error with a deprecated error' do
76
- expect { raise Faraday::ClientError, nil }.to raise_error(Faraday::Error::ClientError)
77
- end
78
-
79
- it 'allows rescuing of a current error with a current error' do
80
- expect { raise Faraday::ClientError, nil }.to raise_error(Faraday::ClientError)
81
- end
82
-
83
- it 'allows rescuing of a deprecated error with a deprecated error' do
84
- expect { raise Faraday::Error::ClientError, nil }.to raise_error(Faraday::Error::ClientError)
85
- end
86
-
87
- it 'allows rescuing of a deprecated error with a current error' do
88
- expect { raise Faraday::Error::ClientError, nil }.to raise_error(Faraday::ClientError)
89
- end
90
- end
91
-
92
- def with_warn_squelching
93
- stderr_catcher = StringIO.new
94
- original_stderr = $stderr
95
- $stderr = stderr_catcher
96
- result = yield if block_given?
97
- [stderr_catcher.tap(&:rewind).string, result]
98
- ensure
99
- $stderr = original_stderr
100
- end
101
44
  end
102
45
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Middleware do
4
+ subject { described_class.new(app) }
5
+
6
+ describe '#close' do
7
+ context "with app that doesn't support \#close" do
8
+ let(:app) { double }
9
+
10
+ it 'should issue warning' do
11
+ expect(subject).to receive(:warn)
12
+ subject.close
13
+ end
14
+ end
15
+
16
+ context "with app that supports \#close" do
17
+ let(:app) { double }
18
+
19
+ it 'should issue warning' do
20
+ expect(app).to receive(:close)
21
+ expect(subject).to_not receive(:warn)
22
+ subject.close
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Env do
4
+ subject(:env) { described_class.new }
5
+
6
+ it 'allows to access members' do
7
+ expect(env.method).to be_nil
8
+ env.method = :get
9
+ expect(env.method).to eq(:get)
10
+ end
11
+
12
+ it 'allows to access symbol non members' do
13
+ expect(env[:custom]).to be_nil
14
+ env[:custom] = :boom
15
+ expect(env[:custom]).to eq(:boom)
16
+ end
17
+
18
+ it 'allows to access string non members' do
19
+ expect(env['custom']).to be_nil
20
+ env['custom'] = :boom
21
+ expect(env['custom']).to eq(:boom)
22
+ end
23
+
24
+ it 'ignores false when fetching' do
25
+ ssl = Faraday::SSLOptions.new
26
+ ssl.verify = false
27
+ expect(ssl.fetch(:verify, true)).to be_falsey
28
+ end
29
+
30
+ it 'retains custom members' do
31
+ env[:foo] = 'custom 1'
32
+ env[:bar] = :custom_2
33
+ env2 = Faraday::Env.from(env)
34
+ env2[:baz] = 'custom 3'
35
+
36
+ expect(env2[:foo]).to eq('custom 1')
37
+ expect(env2[:bar]).to eq(:custom_2)
38
+ expect(env[:baz]).to be_nil
39
+ end
40
+
41
+ describe '#body' do
42
+ subject(:env) { described_class.from(body: { foo: 'bar' }) }
43
+
44
+ context 'when response is not finished yet' do
45
+ it 'returns the request body' do
46
+ expect(env.body).to eq(foo: 'bar')
47
+ end
48
+ end
49
+
50
+ context 'when response is finished' do
51
+ before do
52
+ env.status = 200
53
+ env.body = { bar: 'foo' }
54
+ env.response = Faraday::Response.new(env)
55
+ end
56
+
57
+ it 'returns the response body' do
58
+ expect(env.body).to eq(bar: 'foo')
59
+ end
60
+
61
+ it 'allows to access request_body' do
62
+ expect(env.request_body).to eq(foo: 'bar')
63
+ end
64
+
65
+ it 'allows to access response_body' do
66
+ expect(env.response_body).to eq(bar: 'foo')
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,297 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Options do
4
+ SubOptions = Class.new(Faraday::Options.new(:sub_a, :sub_b))
5
+ class ParentOptions < Faraday::Options.new(:a, :b, :c)
6
+ options c: SubOptions
7
+ end
8
+
9
+ describe '#merge' do
10
+ it 'merges options with hashes' do
11
+ options = ParentOptions.new(1)
12
+ expect(options.a).to eq(1)
13
+ expect(options.b).to be_nil
14
+
15
+ dup = options.merge a: 2, b: 3
16
+ expect(dup.a).to eq(2)
17
+ expect(dup.b).to eq(3)
18
+ expect(options.a).to eq(1)
19
+ expect(options.b).to be_nil
20
+ end
21
+
22
+ it 'deeply merges two options' do
23
+ sub_opts1 = SubOptions.from(sub_a: 3)
24
+ sub_opts2 = SubOptions.from(sub_b: 4)
25
+ opt1 = ParentOptions.from(a: 1, c: sub_opts1)
26
+ opt2 = ParentOptions.from(b: 2, c: sub_opts2)
27
+
28
+ merged = opt1.merge(opt2)
29
+
30
+ expected_sub_opts = SubOptions.from(sub_a: 3, sub_b: 4)
31
+ expected = ParentOptions.from(a: 1, b: 2, c: expected_sub_opts)
32
+ expect(merged).to eq(expected)
33
+ end
34
+
35
+ it 'deeply merges options with hashes' do
36
+ sub_opts1 = SubOptions.from(sub_a: 3)
37
+ sub_opts2 = { sub_b: 4 }
38
+ opt1 = ParentOptions.from(a: 1, c: sub_opts1)
39
+ opt2 = { b: 2, c: sub_opts2 }
40
+
41
+ merged = opt1.merge(opt2)
42
+
43
+ expected_sub_opts = SubOptions.from(sub_a: 3, sub_b: 4)
44
+ expected = ParentOptions.from(a: 1, b: 2, c: expected_sub_opts)
45
+ expect(merged).to eq(expected)
46
+ end
47
+
48
+ it 'deeply merges options with nil' do
49
+ sub_opts = SubOptions.new(3, 4)
50
+ options = ParentOptions.new(1, 2, sub_opts)
51
+ expect(options.a).to eq(1)
52
+ expect(options.b).to eq(2)
53
+ expect(options.c.sub_a).to eq(3)
54
+ expect(options.c.sub_b).to eq(4)
55
+
56
+ options2 = ParentOptions.from(b: 5, c: nil)
57
+
58
+ merged = options.merge(options2)
59
+
60
+ expect(merged.b).to eq(5)
61
+ expect(merged.c).to eq(sub_opts)
62
+ end
63
+
64
+ it 'deeply merges options with options having nil sub-options' do
65
+ options = ParentOptions.from(a: 1)
66
+
67
+ sub_opts = SubOptions.new(3, 4)
68
+ options2 = ParentOptions.from(b: 2, c: sub_opts)
69
+
70
+ expect(options.a).to eq(1)
71
+ expect(options2.b).to eq(2)
72
+ expect(options2.c.sub_a).to eq(3)
73
+ expect(options2.c.sub_b).to eq(4)
74
+
75
+ merged = options.merge(options2)
76
+
77
+ expect(merged.c).to eq(sub_opts)
78
+ end
79
+
80
+ describe '#dup' do
81
+ it 'duplicate options but not sub-options' do
82
+ sub_opts = SubOptions.from(sub_a: 3)
83
+ opts = ParentOptions.from(b: 1, c: sub_opts)
84
+
85
+ duped = opts.dup
86
+ duped.b = 2
87
+ duped.c.sub_a = 4
88
+
89
+ expect(opts.b).to eq(1)
90
+ expect(opts.c.sub_a).to eq(4)
91
+ end
92
+ end
93
+
94
+ describe '#deep_dup' do
95
+ it 'duplicate options and also suboptions' do
96
+ sub_opts = SubOptions.from(sub_a: 3)
97
+ opts = ParentOptions.from(b: 1, c: sub_opts)
98
+
99
+ duped = opts.deep_dup
100
+ duped.b = 2
101
+ duped.c.sub_a = 4
102
+
103
+ expect(opts.b).to eq(1)
104
+ expect(opts.c.sub_a).to eq(3)
105
+ end
106
+ end
107
+
108
+ describe '#clear' do
109
+ it 'clears the options' do
110
+ options = SubOptions.new(1)
111
+ expect(options.empty?).not_to be_truthy
112
+ options.clear
113
+ expect(options.empty?).to be_truthy
114
+ end
115
+ end
116
+
117
+ describe '#empty?' do
118
+ it 'returns true only if all options are nil' do
119
+ options = SubOptions.new
120
+ expect(options.empty?).to be_truthy
121
+ options.sub_a = 1
122
+ expect(options.empty?).not_to be_truthy
123
+ options.delete(:sub_a)
124
+ expect(options.empty?).to be_truthy
125
+ end
126
+ end
127
+
128
+ describe '#each_key' do
129
+ it 'allows to iterate through keys' do
130
+ options = ParentOptions.new(1, 2, 3)
131
+ enum = options.each_key
132
+ expect(enum.next.to_sym).to eq(:a)
133
+ expect(enum.next.to_sym).to eq(:b)
134
+ expect(enum.next.to_sym).to eq(:c)
135
+ end
136
+ end
137
+
138
+ describe '#key?' do
139
+ it 'returns true if the key exists and is not nil' do
140
+ options = SubOptions.new
141
+ expect(options.key?(:sub_a)).not_to be_truthy
142
+ options.sub_a = 1
143
+ expect(options.key?(:sub_a)).to be_truthy
144
+ end
145
+ end
146
+
147
+ describe '#each_value' do
148
+ it 'allows to iterate through values' do
149
+ options = ParentOptions.new(1, 2, 3)
150
+ enum = options.each_value
151
+ expect(enum.next).to eq(1)
152
+ expect(enum.next).to eq(2)
153
+ expect(enum.next).to eq(3)
154
+ end
155
+ end
156
+
157
+ describe '#value?' do
158
+ it 'returns true if any key has that value' do
159
+ options = SubOptions.new
160
+ expect(options.value?(1)).not_to be_truthy
161
+ options.sub_a = 1
162
+ expect(options.value?(1)).to be_truthy
163
+ end
164
+ end
165
+
166
+ describe '#update' do
167
+ it 'updates options from hashes' do
168
+ options = ParentOptions.new(1)
169
+ expect(options.a).to eq(1)
170
+ expect(options.b).to be_nil
171
+
172
+ updated = options.update a: 2, b: 3
173
+ expect(options.a).to eq(2)
174
+ expect(options.b).to eq(3)
175
+ expect(updated).to eq(options)
176
+ end
177
+ end
178
+
179
+ describe '#delete' do
180
+ it 'allows to remove value for key' do
181
+ options = ParentOptions.new(1)
182
+ expect(options.a).to eq(1)
183
+ expect(options.delete(:a)).to eq(1)
184
+ expect(options.a).to be_nil
185
+ end
186
+ end
187
+
188
+ describe '#from' do
189
+ it { expect { ParentOptions.from invalid: 1 }.to raise_error(NoMethodError) }
190
+
191
+ it 'works with options' do
192
+ options = ParentOptions.new(1)
193
+
194
+ value = ParentOptions.from(options)
195
+ expect(value.a).to eq(1)
196
+ expect(value.b).to be_nil
197
+ end
198
+
199
+ it 'works with options with sub object' do
200
+ sub = SubOptions.new(1)
201
+ options = ParentOptions.from a: 1, c: sub
202
+ expect(options).to be_a_kind_of(ParentOptions)
203
+ expect(options.a).to eq(1)
204
+ expect(options.b).to be_nil
205
+ expect(options.c).to be_a_kind_of(SubOptions)
206
+ expect(options.c.sub_a).to eq(1)
207
+ end
208
+
209
+ it 'works with hash' do
210
+ options = ParentOptions.from a: 1
211
+ expect(options).to be_a_kind_of(ParentOptions)
212
+ expect(options.a).to eq(1)
213
+ expect(options.b).to be_nil
214
+ end
215
+
216
+ it 'works with hash with sub object' do
217
+ options = ParentOptions.from a: 1, c: { sub_a: 1 }
218
+ expect(options).to be_a_kind_of(ParentOptions)
219
+ expect(options.a).to eq(1)
220
+ expect(options.b).to be_nil
221
+ expect(options.c).to be_a_kind_of(SubOptions)
222
+ expect(options.c.sub_a).to eq(1)
223
+ end
224
+
225
+ it 'works with deep hash' do
226
+ hash = { b: 1 }
227
+ options = ParentOptions.from a: hash
228
+ expect(options.a[:b]).to eq(1)
229
+
230
+ hash[:b] = 2
231
+ expect(options.a[:b]).to eq(1)
232
+
233
+ options.a[:b] = 3
234
+ expect(hash[:b]).to eq(2)
235
+ expect(options.a[:b]).to eq(3)
236
+ end
237
+
238
+ it 'works with nil' do
239
+ options = ParentOptions.from(nil)
240
+ expect(options).to be_a_kind_of(ParentOptions)
241
+ expect(options.a).to be_nil
242
+ expect(options.b).to be_nil
243
+ end
244
+
245
+ it 'respects inheritance' do
246
+ subclass = Class.new(ParentOptions)
247
+ options = subclass.from(c: { sub_a: 'hello' })
248
+ expect(options.c).to be_a_kind_of(SubOptions)
249
+ expect(options.c.sub_a).to eq('hello')
250
+ end
251
+ end
252
+
253
+ describe '#memoized' do
254
+ subject(:options_class) { Class.new(ParentOptions) }
255
+ it 'requires block' do
256
+ expect { options_class.memoized(:a) }.to raise_error(ArgumentError)
257
+ end
258
+
259
+ it 'accepts block' do
260
+ options_class.memoized(:a) { :foo }
261
+ expect(options_class.new.a).to eql(:foo)
262
+ end
263
+ end
264
+
265
+ describe '#fetch' do
266
+ subject { SubOptions.new }
267
+
268
+ context 'when the fetched key has no value' do
269
+ it 'uses falsey default' do
270
+ expect(subject.fetch(:sub_a, false) { |_| :blah }).to be_falsey
271
+ end
272
+
273
+ it 'accepts block' do
274
+ expect(subject.fetch(:sub_a) { |k| "yo #{k.inspect}" }).to eq('yo :sub_a')
275
+ end
276
+
277
+ it 'needs a default if key is missing' do
278
+ expect { subject.fetch(:sub_a) }.to raise_error(Faraday::Options.fetch_error_class)
279
+ end
280
+ end
281
+
282
+ context 'when the fetched key has a value' do
283
+ before do
284
+ subject.sub_a = 1
285
+ end
286
+
287
+ it 'grabs value' do
288
+ expect(subject.fetch(:sub_a, false) { |_| :blah }).to eq(1)
289
+ end
290
+
291
+ it 'works with key' do
292
+ expect(subject.fetch(:sub_a)).to eq(1)
293
+ end
294
+ end
295
+ end
296
+ end
297
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::ProxyOptions do
4
+ describe '#from' do
5
+ it 'works with string' do
6
+ options = Faraday::ProxyOptions.from 'http://user:pass@example.org'
7
+ expect(options.user).to eq('user')
8
+ expect(options.password).to eq('pass')
9
+ expect(options.uri).to be_a_kind_of(URI)
10
+ expect(options.path).to eq('')
11
+ expect(options.port).to eq(80)
12
+ expect(options.host).to eq('example.org')
13
+ expect(options.scheme).to eq('http')
14
+ expect(options.inspect).to match('#<Faraday::ProxyOptions uri=')
15
+ end
16
+
17
+ it 'works with nil' do
18
+ options = Faraday::ProxyOptions.from nil
19
+ expect(options).to be_a_kind_of(Faraday::ProxyOptions)
20
+ expect(options.inspect).to eq('#<Faraday::ProxyOptions (empty)>')
21
+ end
22
+
23
+ it 'works with no auth' do
24
+ proxy = Faraday::ProxyOptions.from 'http://example.org'
25
+ expect(proxy.user).to be_nil
26
+ expect(proxy.password).to be_nil
27
+ end
28
+ end
29
+
30
+ it 'allows hash access' do
31
+ proxy = Faraday::ProxyOptions.from 'http://a%40b:pw%20d@example.org'
32
+ expect(proxy.user).to eq('a@b')
33
+ expect(proxy[:user]).to eq('a@b')
34
+ expect(proxy.password).to eq('pw d')
35
+ expect(proxy[:password]).to eq('pw d')
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::RequestOptions do
4
+ subject(:options) { Faraday::RequestOptions.new }
5
+
6
+ it 'allows to set the request proxy' do
7
+ expect(options.proxy).to be_nil
8
+
9
+ expect { options[:proxy] = { booya: 1 } }.to raise_error(NoMethodError)
10
+
11
+ options[:proxy] = { user: 'user' }
12
+ expect(options.proxy).to be_a_kind_of(Faraday::ProxyOptions)
13
+ expect(options.proxy.user).to eq('user')
14
+
15
+ options.proxy = nil
16
+ expect(options.proxy).to be_nil
17
+ expect(options.inspect).to eq('#<Faraday::RequestOptions (empty)>')
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack/utils'
4
+
5
+ RSpec.describe Faraday::FlatParamsEncoder do
6
+ it_behaves_like 'a params encoder'
7
+
8
+ it 'decodes arrays' do
9
+ query = 'a=one&a=two&a=three'
10
+ expected = { 'a' => %w[one two three] }
11
+ expect(subject.decode(query)).to eq(expected)
12
+ end
13
+
14
+ it 'decodes boolean values' do
15
+ query = 'a=true&b=false'
16
+ expected = { 'a' => 'true', 'b' => 'false' }
17
+ expect(subject.decode(query)).to eq(expected)
18
+ end
19
+
20
+ it 'encodes boolean values' do
21
+ params = { a: true, b: false }
22
+ expect(subject.encode(params)).to eq('a=true&b=false')
23
+ end
24
+
25
+ it 'encodes boolean values in array' do
26
+ params = { a: [true, false] }
27
+ expect(subject.encode(params)).to eq('a=true&a=false')
28
+ end
29
+
30
+ it 'encodes empty array in hash' do
31
+ params = { a: [] }
32
+ expect(subject.encode(params)).to eq('a=')
33
+ end
34
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack/utils'
4
+
5
+ RSpec.describe Faraday::NestedParamsEncoder do
6
+ it_behaves_like 'a params encoder'
7
+
8
+ it 'decodes arrays' do
9
+ query = 'a[1]=one&a[2]=two&a[3]=three'
10
+ expected = { 'a' => %w[one two three] }
11
+ expect(subject.decode(query)).to eq(expected)
12
+ end
13
+
14
+ it 'decodes hashes' do
15
+ query = 'a[b1]=one&a[b2]=two&a[b][c]=foo'
16
+ expected = { 'a' => { 'b1' => 'one', 'b2' => 'two', 'b' => { 'c' => 'foo' } } }
17
+ expect(subject.decode(query)).to eq(expected)
18
+ end
19
+
20
+ it 'decodes nested arrays rack compat' do
21
+ query = 'a[][one]=1&a[][two]=2&a[][one]=3&a[][two]=4'
22
+ expected = Rack::Utils.parse_nested_query(query)
23
+ expect(subject.decode(query)).to eq(expected)
24
+ end
25
+
26
+ it 'decodes nested array mixed types' do
27
+ query = 'a[][one]=1&a[]=2&a[]=&a[]'
28
+ expected = Rack::Utils.parse_nested_query(query)
29
+ expect(subject.decode(query)).to eq(expected)
30
+ end
31
+
32
+ it 'decodes nested ignores invalid array' do
33
+ query = '[][a]=1&b=2'
34
+ expected = { 'a' => '1', 'b' => '2' }
35
+ expect(subject.decode(query)).to eq(expected)
36
+ end
37
+
38
+ it 'decodes nested ignores repeated array notation' do
39
+ query = 'a[][][]=1'
40
+ expected = { 'a' => ['1'] }
41
+ expect(subject.decode(query)).to eq(expected)
42
+ end
43
+
44
+ it 'decodes nested ignores malformed keys' do
45
+ query = '=1&[]=2'
46
+ expected = {}
47
+ expect(subject.decode(query)).to eq(expected)
48
+ end
49
+
50
+ it 'decodes nested subkeys dont have to be in brackets' do
51
+ query = 'a[b]c[d]e=1'
52
+ expected = { 'a' => { 'b' => { 'c' => { 'd' => { 'e' => '1' } } } } }
53
+ expect(subject.decode(query)).to eq(expected)
54
+ end
55
+
56
+ it 'decodes nested final value overrides any type' do
57
+ query = 'a[b][c]=1&a[b]=2'
58
+ expected = { 'a' => { 'b' => '2' } }
59
+ expect(subject.decode(query)).to eq(expected)
60
+ end
61
+
62
+ it 'encodes rack compat' do
63
+ params = { a: [{ one: '1', two: '2' }, '3', ''] }
64
+ result = Faraday::Utils.unescape(Faraday::NestedParamsEncoder.encode(params)).split('&')
65
+ expected = Rack::Utils.build_nested_query(params).split('&')
66
+ expect(result).to match_array(expected)
67
+ end
68
+
69
+ it 'encodes empty string array value' do
70
+ expected = 'baz=&foo%5Bbar%5D='
71
+ result = Faraday::NestedParamsEncoder.encode(foo: { bar: '' }, baz: '')
72
+ expect(result).to eq(expected)
73
+ end
74
+
75
+ it 'encodes nil array value' do
76
+ expected = 'baz&foo%5Bbar%5D'
77
+ result = Faraday::NestedParamsEncoder.encode(foo: { bar: nil }, baz: nil)
78
+ expect(result).to eq(expected)
79
+ end
80
+
81
+ it 'encodes empty array value' do
82
+ expected = 'baz%5B%5D&foo%5Bbar%5D%5B%5D'
83
+ result = Faraday::NestedParamsEncoder.encode(foo: { bar: [] }, baz: [])
84
+ expect(result).to eq(expected)
85
+ end
86
+
87
+ it 'encodes boolean values' do
88
+ params = { a: true, b: false }
89
+ expect(subject.encode(params)).to eq('a=true&b=false')
90
+ end
91
+
92
+ it 'encodes boolean values in array' do
93
+ params = { a: [true, false] }
94
+ expect(subject.encode(params)).to eq('a%5B%5D=true&a%5B%5D=false')
95
+ end
96
+
97
+ shared_examples 'a wrong decoding' do
98
+ it do
99
+ expect { subject.decode(query) }.to raise_error(TypeError) do |e|
100
+ expect(e.message).to eq(error_message)
101
+ end
102
+ end
103
+ end
104
+
105
+ context 'when expecting hash but getting string' do
106
+ let(:query) { 'a=1&a[b]=2' }
107
+ let(:error_message) { "expected Hash (got String) for param `a'" }
108
+ it_behaves_like 'a wrong decoding'
109
+ end
110
+
111
+ context 'when expecting hash but getting array' do
112
+ let(:query) { 'a[]=1&a[b]=2' }
113
+ let(:error_message) { "expected Hash (got Array) for param `a'" }
114
+ it_behaves_like 'a wrong decoding'
115
+ end
116
+
117
+ context 'when expecting nested hash but getting non nested' do
118
+ let(:query) { 'a[b]=1&a[b][c]=2' }
119
+ let(:error_message) { "expected Hash (got String) for param `b'" }
120
+ it_behaves_like 'a wrong decoding'
121
+ end
122
+
123
+ context 'when expecting array but getting hash' do
124
+ let(:query) { 'a[b]=1&a[]=2' }
125
+ let(:error_message) { "expected Array (got Hash) for param `a'" }
126
+ it_behaves_like 'a wrong decoding'
127
+ end
128
+
129
+ context 'when expecting array but getting string' do
130
+ let(:query) { 'a=1&a[]=2' }
131
+ let(:error_message) { "expected Array (got String) for param `a'" }
132
+ it_behaves_like 'a wrong decoding'
133
+ end
134
+ end