httparty 0.14.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of httparty might be problematic. Click here for more details.

Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/.editorconfig +18 -0
  3. data/.github/workflows/ci.yml +23 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop_todo.yml +1 -1
  6. data/{History → Changelog.md} +216 -63
  7. data/Gemfile +6 -1
  8. data/README.md +8 -8
  9. data/bin/httparty +3 -1
  10. data/docs/README.md +108 -37
  11. data/examples/README.md +34 -12
  12. data/examples/aaws.rb +7 -3
  13. data/examples/body_stream.rb +14 -0
  14. data/examples/crack.rb +1 -1
  15. data/examples/custom_parsers.rb +5 -1
  16. data/examples/delicious.rb +4 -4
  17. data/examples/headers_and_user_agents.rb +7 -3
  18. data/examples/idn.rb +10 -0
  19. data/examples/logging.rb +4 -4
  20. data/examples/microsoft_graph.rb +52 -0
  21. data/examples/multipart.rb +22 -0
  22. data/examples/peer_cert.rb +9 -0
  23. data/examples/stackexchange.rb +1 -1
  24. data/examples/stream_download.rb +26 -0
  25. data/examples/tripit_sign_in.rb +1 -1
  26. data/examples/twitter.rb +2 -2
  27. data/examples/whoismyrep.rb +1 -1
  28. data/httparty.gemspec +7 -4
  29. data/lib/httparty/connection_adapter.rb +73 -16
  30. data/lib/httparty/cookie_hash.rb +10 -8
  31. data/lib/httparty/decompressor.rb +92 -0
  32. data/lib/httparty/exceptions.rb +4 -1
  33. data/lib/httparty/hash_conversions.rb +30 -12
  34. data/lib/httparty/headers_processor.rb +32 -0
  35. data/lib/httparty/logger/apache_formatter.rb +31 -6
  36. data/lib/httparty/logger/curl_formatter.rb +9 -7
  37. data/lib/httparty/logger/logger.rb +5 -1
  38. data/lib/httparty/logger/logstash_formatter.rb +61 -0
  39. data/lib/httparty/module_inheritable_attributes.rb +6 -4
  40. data/lib/httparty/net_digest_auth.rb +19 -19
  41. data/lib/httparty/parser.rb +25 -14
  42. data/lib/httparty/request/body.rb +98 -0
  43. data/lib/httparty/request/multipart_boundary.rb +13 -0
  44. data/lib/httparty/request.rb +137 -110
  45. data/lib/httparty/response/headers.rb +23 -19
  46. data/lib/httparty/response.rb +81 -22
  47. data/lib/httparty/response_fragment.rb +21 -0
  48. data/lib/httparty/text_encoder.rb +72 -0
  49. data/lib/httparty/utils.rb +13 -0
  50. data/lib/httparty/version.rb +3 -1
  51. data/lib/httparty.rb +79 -30
  52. data/website/css/common.css +1 -1
  53. metadata +37 -103
  54. data/.travis.yml +0 -9
  55. data/features/basic_authentication.feature +0 -20
  56. data/features/command_line.feature +0 -95
  57. data/features/deals_with_http_error_codes.feature +0 -26
  58. data/features/digest_authentication.feature +0 -30
  59. data/features/handles_compressed_responses.feature +0 -27
  60. data/features/handles_multiple_formats.feature +0 -57
  61. data/features/steps/env.rb +0 -27
  62. data/features/steps/httparty_response_steps.rb +0 -56
  63. data/features/steps/httparty_steps.rb +0 -43
  64. data/features/steps/mongrel_helper.rb +0 -127
  65. data/features/steps/remote_service_steps.rb +0 -92
  66. data/features/supports_read_timeout_option.feature +0 -13
  67. data/features/supports_redirection.feature +0 -22
  68. data/features/supports_timeout_option.feature +0 -13
  69. data/spec/fixtures/delicious.xml +0 -23
  70. data/spec/fixtures/empty.xml +0 -0
  71. data/spec/fixtures/google.html +0 -3
  72. data/spec/fixtures/ssl/generate.sh +0 -29
  73. data/spec/fixtures/ssl/generated/1fe462c2.0 +0 -16
  74. data/spec/fixtures/ssl/generated/bogushost.crt +0 -13
  75. data/spec/fixtures/ssl/generated/ca.crt +0 -16
  76. data/spec/fixtures/ssl/generated/ca.key +0 -15
  77. data/spec/fixtures/ssl/generated/selfsigned.crt +0 -14
  78. data/spec/fixtures/ssl/generated/server.crt +0 -13
  79. data/spec/fixtures/ssl/generated/server.key +0 -15
  80. data/spec/fixtures/ssl/openssl-exts.cnf +0 -9
  81. data/spec/fixtures/twitter.csv +0 -2
  82. data/spec/fixtures/twitter.json +0 -1
  83. data/spec/fixtures/twitter.xml +0 -403
  84. data/spec/fixtures/undefined_method_add_node_for_nil.xml +0 -2
  85. data/spec/httparty/connection_adapter_spec.rb +0 -495
  86. data/spec/httparty/cookie_hash_spec.rb +0 -100
  87. data/spec/httparty/exception_spec.rb +0 -45
  88. data/spec/httparty/hash_conversions_spec.rb +0 -49
  89. data/spec/httparty/logger/apache_formatter_spec.rb +0 -41
  90. data/spec/httparty/logger/curl_formatter_spec.rb +0 -119
  91. data/spec/httparty/logger/logger_spec.rb +0 -38
  92. data/spec/httparty/net_digest_auth_spec.rb +0 -240
  93. data/spec/httparty/parser_spec.rb +0 -173
  94. data/spec/httparty/request_spec.rb +0 -1183
  95. data/spec/httparty/response_spec.rb +0 -291
  96. data/spec/httparty/ssl_spec.rb +0 -74
  97. data/spec/httparty_spec.rb +0 -872
  98. data/spec/spec_helper.rb +0 -59
  99. data/spec/support/ssl_test_helper.rb +0 -47
  100. data/spec/support/ssl_test_server.rb +0 -80
  101. data/spec/support/stub_response.rb +0 -49
@@ -1,41 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
-
3
- RSpec.describe HTTParty::Logger::ApacheFormatter do
4
- let(:subject) { described_class.new(logger_double, :info) }
5
- let(:logger_double) { double('Logger') }
6
- let(:request_double) { double('Request', http_method: Net::HTTP::Get, path: "http://my.domain.com/my_path") }
7
- let(:request_time) { Time.new.strftime("%Y-%m-%d %H:%M:%S %z") }
8
-
9
- before do
10
- subject.current_time = request_time
11
- expect(logger_double).to receive(:info).with(log_message)
12
- end
13
-
14
- describe "#format" do
15
- let(:log_message) { "[HTTParty] [#{request_time}] 302 \"GET http://my.domain.com/my_path\" - " }
16
-
17
- it "formats a response in a style that resembles apache's access log" do
18
- response_double = double(
19
- code: 302,
20
- :[] => nil
21
- )
22
-
23
- subject.format(request_double, response_double)
24
- end
25
-
26
- context 'when there is a parsed response' do
27
- let(:log_message) { "[HTTParty] [#{request_time}] 200 \"GET http://my.domain.com/my_path\" 512 "}
28
-
29
- it "can handle the Content-Length header" do
30
- # Simulate a parsed response that is an array, where accessing a string key will raise an error. See Issue #299.
31
- response_double = double(
32
- code: 200,
33
- headers: { 'Content-Length' => 512 }
34
- )
35
- allow(response_double).to receive(:[]).with('Content-Length').and_raise(TypeError.new('no implicit conversion of String into Integer'))
36
-
37
- subject.format(request_double, response_double)
38
- end
39
- end
40
- end
41
- end
@@ -1,119 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
-
3
- RSpec.describe HTTParty::Logger::CurlFormatter do
4
- describe "#format" do
5
- let(:logger) { double('Logger') }
6
- let(:response_object) { Net::HTTPOK.new('1.1', 200, 'OK') }
7
- let(:parsed_response) { lambda { {"foo" => "bar"} } }
8
-
9
- let(:response) do
10
- HTTParty::Response.new(request, response_object, parsed_response)
11
- end
12
-
13
- let(:request) do
14
- HTTParty::Request.new(Net::HTTP::Get, 'http://foo.bar.com/')
15
- end
16
-
17
- subject { described_class.new(logger, :info) }
18
-
19
- before do
20
- allow(logger).to receive(:info)
21
- allow(request).to receive(:raw_body).and_return('content')
22
- allow(response_object).to receive_messages(body: "{foo:'bar'}")
23
- response_object['header-key'] = 'header-value'
24
-
25
- subject.format request, response
26
- end
27
-
28
- context 'when request is logged' do
29
- context "and request's option 'base_uri' is not present" do
30
- it 'logs url' do
31
- expect(logger).to have_received(:info).with(/\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/foo.bar.com/)
32
- end
33
- end
34
-
35
- context "and request's option 'base_uri' is present" do
36
- let(:request) do
37
- HTTParty::Request.new(Net::HTTP::Get, '/path', base_uri: 'http://foo.bar.com')
38
- end
39
-
40
- it 'logs url' do
41
- expect(logger).to have_received(:info).with(/\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/foo.bar.com\/path/)
42
- end
43
- end
44
-
45
- context 'and headers are not present' do
46
- it 'not log Headers' do
47
- expect(logger).not_to have_received(:info).with(/Headers/)
48
- end
49
- end
50
-
51
- context 'and headers are present' do
52
- let(:request) do
53
- HTTParty::Request.new(Net::HTTP::Get, '/path', base_uri: 'http://foo.bar.com', headers: { key: 'value' })
54
- end
55
-
56
- it 'logs Headers' do
57
- expect(logger).to have_received(:info).with(/Headers/)
58
- end
59
-
60
- it 'logs headers keys' do
61
- expect(logger).to have_received(:info).with(/key: value/)
62
- end
63
- end
64
-
65
- context 'and query is not present' do
66
- it 'not logs Query' do
67
- expect(logger).not_to have_received(:info).with(/Query/)
68
- end
69
- end
70
-
71
- context 'and query is present' do
72
- let(:request) do
73
- HTTParty::Request.new(Net::HTTP::Get, '/path', query: { key: 'value' })
74
- end
75
-
76
- it 'logs Query' do
77
- expect(logger).to have_received(:info).with(/Query/)
78
- end
79
-
80
- it 'logs query params' do
81
- expect(logger).to have_received(:info).with(/key: value/)
82
- end
83
- end
84
-
85
- context 'when request raw_body is present' do
86
- it 'not logs request body' do
87
- expect(logger).to have_received(:info).with(/content/)
88
- end
89
- end
90
- end
91
-
92
- context 'when response is logged' do
93
- it 'logs http version and response code' do
94
- expect(logger).to have_received(:info).with(/HTTP\/1.1 200/)
95
- end
96
-
97
- it 'logs headers' do
98
- expect(logger).to have_received(:info).with(/Header-key: header-value/)
99
- end
100
-
101
- it 'logs body' do
102
- expect(logger).to have_received(:info).with(/{foo:'bar'}/)
103
- end
104
- end
105
-
106
- it "formats a response in a style that resembles a -v curl" do
107
- logger_double = double
108
- expect(logger_double).to receive(:info).with(
109
- /\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/localhost/)
110
-
111
- subject = described_class.new(logger_double, :info)
112
-
113
- stub_http_response_with("google.html")
114
-
115
- response = HTTParty::Request.new.perform
116
- subject.format(response.request, response)
117
- end
118
- end
119
- end
@@ -1,38 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
-
3
- RSpec.describe HTTParty::Logger do
4
- describe ".build" do
5
- subject { HTTParty::Logger }
6
-
7
- it "defaults level to :info" do
8
- logger_double = double
9
- expect(subject.build(logger_double, nil, nil).level).to eq(:info)
10
- end
11
-
12
- it "defaults format to :apache" do
13
- logger_double = double
14
- expect(subject.build(logger_double, nil, nil)).to be_an_instance_of(HTTParty::Logger::ApacheFormatter)
15
- end
16
-
17
- it "builds :curl style logger" do
18
- logger_double = double
19
- expect(subject.build(logger_double, nil, :curl)).to be_an_instance_of(HTTParty::Logger::CurlFormatter)
20
- end
21
-
22
- it "builds :custom style logger" do
23
- CustomFormatter = Class.new(HTTParty::Logger::CurlFormatter)
24
- HTTParty::Logger.add_formatter(:custom, CustomFormatter)
25
-
26
- logger_double = double
27
- expect(subject.build(logger_double, nil, :custom)).
28
- to be_an_instance_of(CustomFormatter)
29
- end
30
- it "raises error when formatter exists" do
31
- CustomFormatter2= Class.new(HTTParty::Logger::CurlFormatter)
32
- HTTParty::Logger.add_formatter(:custom2, CustomFormatter2)
33
-
34
- expect{ HTTParty::Logger.add_formatter(:custom2, CustomFormatter2) }.
35
- to raise_error HTTParty::Error
36
- end
37
- end
38
- end
@@ -1,240 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
- RSpec.describe Net::HTTPHeader::DigestAuthenticator do
4
- def setup_digest(response)
5
- digest = Net::HTTPHeader::DigestAuthenticator.new("Mufasa",
6
- "Circle Of Life", "GET", "/dir/index.html", response)
7
- allow(digest).to receive(:random).and_return("deadbeef")
8
- allow(Digest::MD5).to receive(:hexdigest) { |str| "md5(#{str})" }
9
- digest
10
- end
11
-
12
- def authorization_header
13
- @digest.authorization_header.join(", ")
14
- end
15
-
16
- def cookie_header
17
- @digest.cookie_header
18
- end
19
-
20
- context "with a cookie value in the response header" do
21
- before do
22
- @digest = setup_digest({
23
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com"',
24
- 'Set-Cookie' => 'custom-cookie=1234567'
25
- })
26
- end
27
-
28
- it "should set cookie header" do
29
- expect(cookie_header).to include('custom-cookie=1234567')
30
- end
31
- end
32
-
33
- context "without a cookie value in the response header" do
34
- before do
35
- @digest = setup_digest({
36
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com"'
37
- })
38
- end
39
-
40
- it "should set empty cookie header array" do
41
- expect(cookie_header).to eql []
42
- end
43
- end
44
-
45
- context "with an opaque value in the response header" do
46
- before do
47
- @digest = setup_digest({
48
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com", opaque="solid"'
49
- })
50
- end
51
-
52
- it "should set opaque" do
53
- expect(authorization_header).to include('opaque="solid"')
54
- end
55
- end
56
-
57
- context "without an opaque valid in the response header" do
58
- before do
59
- @digest = setup_digest({
60
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com"'
61
- })
62
- end
63
-
64
- it "should not set opaque" do
65
- expect(authorization_header).not_to include("opaque=")
66
- end
67
- end
68
-
69
- context "with specified quality of protection (qop)" do
70
- before do
71
- @digest = setup_digest({
72
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"'
73
- })
74
- end
75
-
76
- it "should set prefix" do
77
- expect(authorization_header).to match(/^Digest /)
78
- end
79
-
80
- it "should set username" do
81
- expect(authorization_header).to include('username="Mufasa"')
82
- end
83
-
84
- it "should set digest-uri" do
85
- expect(authorization_header).to include('uri="/dir/index.html"')
86
- end
87
-
88
- it "should set qop" do
89
- expect(authorization_header).to include('qop="auth"')
90
- end
91
-
92
- it "should set cnonce" do
93
- expect(authorization_header).to include('cnonce="md5(deadbeef)"')
94
- end
95
-
96
- it "should set nonce-count" do
97
- expect(authorization_header).to include("nc=00000001")
98
- end
99
-
100
- it "should set response" do
101
- request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
102
- expect(authorization_header).to include(%(response="#{request_digest}"))
103
- end
104
- end
105
-
106
- context "when quality of protection (qop) is unquoted" do
107
- before do
108
- @digest = setup_digest({
109
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop=auth'
110
- })
111
- end
112
-
113
- it "should still set qop" do
114
- expect(authorization_header).to include('qop="auth"')
115
- end
116
- end
117
-
118
- context "with unspecified quality of protection (qop)" do
119
- before do
120
- @digest = setup_digest({
121
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE"'
122
- })
123
- end
124
-
125
- it "should set prefix" do
126
- expect(authorization_header).to match(/^Digest /)
127
- end
128
-
129
- it "should set username" do
130
- expect(authorization_header).to include('username="Mufasa"')
131
- end
132
-
133
- it "should set digest-uri" do
134
- expect(authorization_header).to include('uri="/dir/index.html"')
135
- end
136
-
137
- it "should not set qop" do
138
- expect(authorization_header).not_to include("qop=")
139
- end
140
-
141
- it "should not set cnonce" do
142
- expect(authorization_header).not_to include("cnonce=")
143
- end
144
-
145
- it "should not set nonce-count" do
146
- expect(authorization_header).not_to include("nc=")
147
- end
148
-
149
- it "should set response" do
150
- request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(GET:/dir/index.html))"
151
- expect(authorization_header).to include(%(response="#{request_digest}"))
152
- end
153
- end
154
-
155
- context "with http basic auth response when net digest auth expected" do
156
- it "should not fail" do
157
- @digest = setup_digest({
158
- 'www-authenticate' => 'WWW-Authenticate: Basic realm="testrealm.com""'
159
- })
160
-
161
- expect(authorization_header).to include("Digest")
162
- end
163
- end
164
-
165
- context "with multiple authenticate headers" do
166
- before do
167
- @digest = setup_digest({
168
- 'www-authenticate' => 'NTLM, Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"'
169
- })
170
- end
171
-
172
- it "should set prefix" do
173
- expect(authorization_header).to match(/^Digest /)
174
- end
175
-
176
- it "should set username" do
177
- expect(authorization_header).to include('username="Mufasa"')
178
- end
179
-
180
- it "should set digest-uri" do
181
- expect(authorization_header).to include('uri="/dir/index.html"')
182
- end
183
-
184
- it "should set qop" do
185
- expect(authorization_header).to include('qop="auth"')
186
- end
187
-
188
- it "should set cnonce" do
189
- expect(authorization_header).to include('cnonce="md5(deadbeef)"')
190
- end
191
-
192
- it "should set nonce-count" do
193
- expect(authorization_header).to include("nc=00000001")
194
- end
195
-
196
- it "should set response" do
197
- request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
198
- expect(authorization_header).to include(%(response="#{request_digest}"))
199
- end
200
- end
201
-
202
- context "with algorithm specified" do
203
- before do
204
- @digest = setup_digest({
205
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5'
206
- })
207
- end
208
-
209
- it "should recognise algorithm was specified" do
210
- expect( @digest.send :algorithm_present? ).to be(true)
211
- end
212
-
213
- it "should set the algorithm header" do
214
- expect(authorization_header).to include('algorithm="MD5"')
215
- end
216
- end
217
-
218
- context "with md5-sess algorithm specified" do
219
- before do
220
- @digest = setup_digest({
221
- 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5-sess'
222
- })
223
- end
224
-
225
- it "should recognise algorithm was specified" do
226
- expect( @digest.send :algorithm_present? ).to be(true)
227
- end
228
-
229
- it "should set the algorithm header" do
230
- expect(authorization_header).to include('algorithm="MD5-sess"')
231
- end
232
-
233
- it "should set response using md5-sess algorithm" do
234
- request_digest = "md5(md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(deadbeef)):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
235
- expect(authorization_header).to include(%(response="#{request_digest}"))
236
- end
237
-
238
- end
239
-
240
- end
@@ -1,173 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
- RSpec.describe HTTParty::Parser do
4
- describe ".SupportedFormats" do
5
- it "returns a hash" do
6
- expect(HTTParty::Parser::SupportedFormats).to be_instance_of(Hash)
7
- end
8
- end
9
-
10
- describe ".call" do
11
- it "generates an HTTParty::Parser instance with the given body and format" do
12
- expect(HTTParty::Parser).to receive(:new).with('body', :plain).and_return(double(parse: nil))
13
- HTTParty::Parser.call('body', :plain)
14
- end
15
-
16
- it "calls #parse on the parser" do
17
- parser = double('Parser')
18
- expect(parser).to receive(:parse)
19
- allow(HTTParty::Parser).to receive_messages(new: parser)
20
- parser = HTTParty::Parser.call('body', :plain)
21
- end
22
- end
23
-
24
- describe ".formats" do
25
- it "returns the SupportedFormats constant" do
26
- expect(HTTParty::Parser.formats).to eq(HTTParty::Parser::SupportedFormats)
27
- end
28
-
29
- it "returns the SupportedFormats constant for subclasses" do
30
- class MyParser < HTTParty::Parser
31
- SupportedFormats = {"application/atom+xml" => :atom}
32
- end
33
- expect(MyParser.formats).to eq({"application/atom+xml" => :atom})
34
- end
35
- end
36
-
37
- describe ".format_from_mimetype" do
38
- it "returns a symbol representing the format mimetype" do
39
- expect(HTTParty::Parser.format_from_mimetype("text/plain")).to eq(:plain)
40
- end
41
-
42
- it "returns nil when the mimetype is not supported" do
43
- expect(HTTParty::Parser.format_from_mimetype("application/atom+xml")).to be_nil
44
- end
45
- end
46
-
47
- describe ".supported_formats" do
48
- it "returns a unique set of supported formats represented by symbols" do
49
- expect(HTTParty::Parser.supported_formats).to eq(HTTParty::Parser::SupportedFormats.values.uniq)
50
- end
51
- end
52
-
53
- describe ".supports_format?" do
54
- it "returns true for a supported format" do
55
- allow(HTTParty::Parser).to receive_messages(supported_formats: [:json])
56
- expect(HTTParty::Parser.supports_format?(:json)).to be_truthy
57
- end
58
-
59
- it "returns false for an unsupported format" do
60
- allow(HTTParty::Parser).to receive_messages(supported_formats: [])
61
- expect(HTTParty::Parser.supports_format?(:json)).to be_falsey
62
- end
63
- end
64
-
65
- describe "#parse" do
66
- before do
67
- @parser = HTTParty::Parser.new('body', :json)
68
- end
69
-
70
- it "attempts to parse supported formats" do
71
- allow(@parser).to receive_messages(supports_format?: true)
72
- expect(@parser).to receive(:parse_supported_format)
73
- @parser.parse
74
- end
75
-
76
- it "returns the unparsed body when the format is unsupported" do
77
- allow(@parser).to receive_messages(supports_format?: false)
78
- expect(@parser.parse).to eq(@parser.body)
79
- end
80
-
81
- it "returns nil for an empty body" do
82
- allow(@parser).to receive_messages(body: '')
83
- expect(@parser.parse).to be_nil
84
- end
85
-
86
- it "returns nil for a nil body" do
87
- allow(@parser).to receive_messages(body: nil)
88
- expect(@parser.parse).to be_nil
89
- end
90
-
91
- it "returns nil for a 'null' body" do
92
- allow(@parser).to receive_messages(body: "null")
93
- expect(@parser.parse).to be_nil
94
- end
95
-
96
- it "returns nil for a body with spaces only" do
97
- allow(@parser).to receive_messages(body: " ")
98
- expect(@parser.parse).to be_nil
99
- end
100
-
101
- it "does not raise exceptions for bodies with invalid encodings" do
102
- allow(@parser).to receive_messages(body: "\x80")
103
- allow(@parser).to receive_messages(supports_format?: false)
104
- expect(@parser.parse).to_not be_nil
105
- end
106
- end
107
-
108
- describe "#supports_format?" do
109
- it "utilizes the class method to determine if the format is supported" do
110
- expect(HTTParty::Parser).to receive(:supports_format?).with(:json)
111
- parser = HTTParty::Parser.new('body', :json)
112
- parser.send(:supports_format?)
113
- end
114
- end
115
-
116
- describe "#parse_supported_format" do
117
- it "calls the parser for the given format" do
118
- parser = HTTParty::Parser.new('body', :json)
119
- expect(parser).to receive(:json)
120
- parser.send(:parse_supported_format)
121
- end
122
-
123
- context "when a parsing method does not exist for the given format" do
124
- it "raises an exception" do
125
- parser = HTTParty::Parser.new('body', :atom)
126
- expect do
127
- parser.send(:parse_supported_format)
128
- end.to raise_error(NotImplementedError, "HTTParty::Parser has not implemented a parsing method for the :atom format.")
129
- end
130
-
131
- it "raises a useful exception message for subclasses" do
132
- atom_parser = Class.new(HTTParty::Parser) do
133
- def self.name
134
- 'AtomParser'
135
- end
136
- end
137
- parser = atom_parser.new 'body', :atom
138
- expect do
139
- parser.send(:parse_supported_format)
140
- end.to raise_error(NotImplementedError, "AtomParser has not implemented a parsing method for the :atom format.")
141
- end
142
- end
143
- end
144
-
145
- context "parsers" do
146
- subject do
147
- HTTParty::Parser.new('body', nil)
148
- end
149
-
150
- it "parses xml with MultiXml" do
151
- expect(MultiXml).to receive(:parse).with('body')
152
- subject.send(:xml)
153
- end
154
-
155
- it "parses json with JSON" do
156
- expect(JSON).to receive(:parse).with('body', :quirks_mode => true, :allow_nan => true)
157
- subject.send(:json)
158
- end
159
-
160
- it "parses html by simply returning the body" do
161
- expect(subject.send(:html)).to eq('body')
162
- end
163
-
164
- it "parses plain text by simply returning the body" do
165
- expect(subject.send(:plain)).to eq('body')
166
- end
167
-
168
- it "parses csv with CSV" do
169
- expect(CSV).to receive(:parse).with('body')
170
- subject.send(:csv)
171
- end
172
- end
173
- end