dkastner-httparty 0.9.0
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.
- data/.gitignore +10 -0
- data/.travis.yml +8 -0
- data/Gemfile +15 -0
- data/Guardfile +16 -0
- data/History +293 -0
- data/MIT-LICENSE +20 -0
- data/README.md +79 -0
- data/Rakefile +15 -0
- data/bin/httparty +114 -0
- data/cucumber.yml +1 -0
- data/examples/aaws.rb +32 -0
- data/examples/basic.rb +32 -0
- data/examples/crack.rb +19 -0
- data/examples/custom_parsers.rb +67 -0
- data/examples/delicious.rb +37 -0
- data/examples/google.rb +16 -0
- data/examples/headers_and_user_agents.rb +6 -0
- data/examples/nokogiri_html_parser.rb +22 -0
- data/examples/rubyurl.rb +14 -0
- data/examples/tripit_sign_in.rb +33 -0
- data/examples/twitter.rb +31 -0
- data/examples/whoismyrep.rb +10 -0
- data/features/basic_authentication.feature +20 -0
- data/features/command_line.feature +7 -0
- data/features/deals_with_http_error_codes.feature +26 -0
- data/features/digest_authentication.feature +20 -0
- data/features/handles_compressed_responses.feature +19 -0
- data/features/handles_multiple_formats.feature +34 -0
- data/features/steps/env.rb +22 -0
- data/features/steps/httparty_response_steps.rb +26 -0
- data/features/steps/httparty_steps.rb +27 -0
- data/features/steps/mongrel_helper.rb +94 -0
- data/features/steps/remote_service_steps.rb +69 -0
- data/features/supports_redirection.feature +22 -0
- data/features/supports_timeout_option.feature +13 -0
- data/httparty.gemspec +24 -0
- data/lib/httparty.rb +503 -0
- data/lib/httparty/connection_adapter.rb +116 -0
- data/lib/httparty/cookie_hash.rb +22 -0
- data/lib/httparty/core_extensions.rb +32 -0
- data/lib/httparty/exceptions.rb +26 -0
- data/lib/httparty/hash_conversions.rb +51 -0
- data/lib/httparty/module_inheritable_attributes.rb +44 -0
- data/lib/httparty/net_digest_auth.rb +84 -0
- data/lib/httparty/parser.rb +145 -0
- data/lib/httparty/request.rb +243 -0
- data/lib/httparty/response.rb +62 -0
- data/lib/httparty/response/headers.rb +31 -0
- data/lib/httparty/version.rb +3 -0
- data/spec/fixtures/delicious.xml +23 -0
- data/spec/fixtures/empty.xml +0 -0
- data/spec/fixtures/google.html +3 -0
- data/spec/fixtures/ssl/generate.sh +29 -0
- data/spec/fixtures/ssl/generated/1fe462c2.0 +16 -0
- data/spec/fixtures/ssl/generated/bogushost.crt +13 -0
- data/spec/fixtures/ssl/generated/ca.crt +16 -0
- data/spec/fixtures/ssl/generated/ca.key +15 -0
- data/spec/fixtures/ssl/generated/selfsigned.crt +14 -0
- data/spec/fixtures/ssl/generated/server.crt +13 -0
- data/spec/fixtures/ssl/generated/server.key +15 -0
- data/spec/fixtures/ssl/openssl-exts.cnf +9 -0
- data/spec/fixtures/twitter.json +1 -0
- data/spec/fixtures/twitter.xml +403 -0
- data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
- data/spec/httparty/connection_adapter_spec.rb +206 -0
- data/spec/httparty/cookie_hash_spec.rb +70 -0
- data/spec/httparty/net_digest_auth_spec.rb +115 -0
- data/spec/httparty/parser_spec.rb +171 -0
- data/spec/httparty/request_spec.rb +507 -0
- data/spec/httparty/response_spec.rb +214 -0
- data/spec/httparty/ssl_spec.rb +62 -0
- data/spec/httparty_spec.rb +703 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/ssl_test_helper.rb +47 -0
- data/spec/support/ssl_test_server.rb +80 -0
- data/spec/support/stub_response.rb +43 -0
- data/website/css/common.css +47 -0
- data/website/index.html +73 -0
- metadata +190 -0
@@ -0,0 +1,206 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe HTTParty::ConnectionAdapter do
|
4
|
+
|
5
|
+
describe "initialization" do
|
6
|
+
let(:uri) { URI 'http://www.google.com' }
|
7
|
+
it "takes a URI as input" do
|
8
|
+
HTTParty::ConnectionAdapter.new(uri)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "raises an ArgumentError if the uri is nil" do
|
12
|
+
expect { HTTParty::ConnectionAdapter.new(nil) }.to raise_error ArgumentError
|
13
|
+
end
|
14
|
+
|
15
|
+
it "raises an ArgumentError if the uri is a String" do
|
16
|
+
expect { HTTParty::ConnectionAdapter.new('http://www.google.com') }.to raise_error ArgumentError
|
17
|
+
end
|
18
|
+
|
19
|
+
it "sets the uri" do
|
20
|
+
adapter = HTTParty::ConnectionAdapter.new(uri)
|
21
|
+
adapter.uri.should be uri
|
22
|
+
end
|
23
|
+
|
24
|
+
it "also accepts an optional options hash" do
|
25
|
+
HTTParty::ConnectionAdapter.new(uri, {})
|
26
|
+
end
|
27
|
+
|
28
|
+
it "sets the options" do
|
29
|
+
options = {:foo => :bar}
|
30
|
+
adapter = HTTParty::ConnectionAdapter.new(uri, options)
|
31
|
+
adapter.options.should be options
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".call" do
|
36
|
+
it "generates an HTTParty::ConnectionAdapter instance with the given uri and options" do
|
37
|
+
HTTParty::ConnectionAdapter.should_receive(:new).with(@uri, @options).and_return(stub(:connection => nil))
|
38
|
+
HTTParty::ConnectionAdapter.call(@uri, @options)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "calls #connection on the connection adapter" do
|
42
|
+
adapter = mock('Adapter')
|
43
|
+
connection = mock('Connection')
|
44
|
+
adapter.should_receive(:connection).and_return(connection)
|
45
|
+
HTTParty::ConnectionAdapter.stub(:new => adapter)
|
46
|
+
HTTParty::ConnectionAdapter.call(@uri, @options).should be connection
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#connection' do
|
51
|
+
let(:uri) { URI 'http://www.google.com' }
|
52
|
+
let(:options) { Hash.new }
|
53
|
+
let(:adapter) { HTTParty::ConnectionAdapter.new(uri, options) }
|
54
|
+
|
55
|
+
describe "the resulting connection" do
|
56
|
+
subject { adapter.connection }
|
57
|
+
it { should be_an_instance_of Net::HTTP }
|
58
|
+
|
59
|
+
context "using port 80" do
|
60
|
+
let(:uri) { URI 'http://foobar.com' }
|
61
|
+
it { should_not use_ssl }
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when dealing with ssl" do
|
65
|
+
let(:uri) { URI 'https://foobar.com' }
|
66
|
+
|
67
|
+
context "using port 443 for ssl" do
|
68
|
+
let(:uri) { URI 'https://api.foo.com/v1:443' }
|
69
|
+
it { should use_ssl }
|
70
|
+
end
|
71
|
+
|
72
|
+
context "https scheme with default port" do
|
73
|
+
it { should use_ssl }
|
74
|
+
end
|
75
|
+
|
76
|
+
context "https scheme with non-standard port" do
|
77
|
+
let(:uri) { URI 'https://foobar.com:123456' }
|
78
|
+
it { should use_ssl }
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when ssl version is set" do
|
82
|
+
let(:options) { {:ssl_version => :TLSv1} }
|
83
|
+
|
84
|
+
it "sets ssl version" do
|
85
|
+
subject.ssl_version.should == :TLSv1
|
86
|
+
end
|
87
|
+
end if RUBY_VERSION > '1.9'
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when timeout is not set" do
|
91
|
+
it "doesn't set the timeout" do
|
92
|
+
http = mock("http", :null_object => true)
|
93
|
+
http.should_not_receive(:open_timeout=)
|
94
|
+
http.should_not_receive(:read_timeout=)
|
95
|
+
Net::HTTP.stub(:new => http)
|
96
|
+
|
97
|
+
adapter.connection
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when setting timeout" do
|
102
|
+
context "to 5 seconds" do
|
103
|
+
let(:options) { {:timeout => 5} }
|
104
|
+
|
105
|
+
its(:open_timeout) { should == 5 }
|
106
|
+
its(:read_timeout) { should == 5 }
|
107
|
+
end
|
108
|
+
|
109
|
+
context "and timeout is a string" do
|
110
|
+
let(:options) { {:timeout => "five seconds"} }
|
111
|
+
|
112
|
+
it "doesn't set the timeout" do
|
113
|
+
http = mock("http", :null_object => true)
|
114
|
+
http.should_not_receive(:open_timeout=)
|
115
|
+
http.should_not_receive(:read_timeout=)
|
116
|
+
Net::HTTP.stub(:new => http)
|
117
|
+
|
118
|
+
adapter.connection
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "when debug_output" do
|
124
|
+
let(:http) { Net::HTTP.new(uri) }
|
125
|
+
before do
|
126
|
+
Net::HTTP.stub(:new => http)
|
127
|
+
end
|
128
|
+
|
129
|
+
context "is set to $stderr" do
|
130
|
+
let(:options) { {:debug_output => $stderr} }
|
131
|
+
it "has debug output set" do
|
132
|
+
http.should_receive(:set_debug_output).with($stderr)
|
133
|
+
adapter.connection
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "is not provided" do
|
138
|
+
it "does not set_debug_output" do
|
139
|
+
http.should_not_receive(:set_debug_output)
|
140
|
+
adapter.connection
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'when providing proxy address and port' do
|
146
|
+
let(:options) { {:http_proxyaddr => '1.2.3.4', :http_proxyport => 8080} }
|
147
|
+
|
148
|
+
it { should be_a_proxy }
|
149
|
+
its(:proxy_address) { should == '1.2.3.4' }
|
150
|
+
its(:proxy_port) { should == 8080 }
|
151
|
+
|
152
|
+
context 'as well as proxy user and password' do
|
153
|
+
let(:options) do
|
154
|
+
{:http_proxyaddr => '1.2.3.4', :http_proxyport => 8080,
|
155
|
+
:http_proxyuser => 'user', :http_proxypass => 'pass'}
|
156
|
+
end
|
157
|
+
its(:proxy_user) { should == 'user' }
|
158
|
+
its(:proxy_pass) { should == 'pass' }
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "when providing PEM certificates" do
|
163
|
+
let(:pem) { :pem_contents }
|
164
|
+
let(:options) { {:pem => pem, :pem_password => "password"} }
|
165
|
+
|
166
|
+
context "when scheme is https" do
|
167
|
+
let(:uri) { URI 'https://google.com' }
|
168
|
+
let(:cert) { mock("OpenSSL::X509::Certificate") }
|
169
|
+
let(:key) { mock("OpenSSL::PKey::RSA") }
|
170
|
+
|
171
|
+
before do
|
172
|
+
OpenSSL::X509::Certificate.should_receive(:new).with(pem).and_return(cert)
|
173
|
+
OpenSSL::PKey::RSA.should_receive(:new).with(pem, "password").and_return(key)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "uses the provided PEM certificate " do
|
177
|
+
subject.cert.should == cert
|
178
|
+
subject.key.should == key
|
179
|
+
end
|
180
|
+
|
181
|
+
it "will verify the certificate" do
|
182
|
+
subject.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "when scheme is not https" do
|
187
|
+
let(:uri) { URI 'http://google.com' }
|
188
|
+
let(:http) { Net::HTTP.new(uri) }
|
189
|
+
|
190
|
+
before do
|
191
|
+
Net::HTTP.stub(:new => http)
|
192
|
+
OpenSSL::X509::Certificate.should_not_receive(:new).with(pem)
|
193
|
+
OpenSSL::PKey::RSA.should_not_receive(:new).with(pem, "password")
|
194
|
+
http.should_not_receive(:cert=)
|
195
|
+
http.should_not_receive(:key=)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "has no PEM certificate " do
|
199
|
+
subject.cert.should be_nil
|
200
|
+
subject.key.should be_nil
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe HTTParty::CookieHash do
|
4
|
+
before(:each) do
|
5
|
+
@cookie_hash = HTTParty::CookieHash.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "#add_cookies" do
|
9
|
+
describe "with a hash" do
|
10
|
+
it "should add new key/value pairs to the hash" do
|
11
|
+
@cookie_hash.add_cookies(:foo => "bar")
|
12
|
+
@cookie_hash.add_cookies(:rofl => "copter")
|
13
|
+
@cookie_hash.length.should eql(2)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should overwrite any existing key" do
|
17
|
+
@cookie_hash.add_cookies(:foo => "bar")
|
18
|
+
@cookie_hash.add_cookies(:foo => "copter")
|
19
|
+
@cookie_hash.length.should eql(1)
|
20
|
+
@cookie_hash[:foo].should eql("copter")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "with a string" do
|
25
|
+
it "should add new key/value pairs to the hash" do
|
26
|
+
@cookie_hash.add_cookies("first=one; second=two; third")
|
27
|
+
@cookie_hash[:first].should == 'one'
|
28
|
+
@cookie_hash[:second].should == 'two'
|
29
|
+
@cookie_hash[:third].should == nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should overwrite any existing key" do
|
33
|
+
@cookie_hash[:foo] = 'bar'
|
34
|
+
@cookie_hash.add_cookies("foo=tar")
|
35
|
+
@cookie_hash.length.should eql(1)
|
36
|
+
@cookie_hash[:foo].should eql("tar")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'with other class' do
|
41
|
+
it "should error" do
|
42
|
+
lambda {
|
43
|
+
@cookie_hash.add_cookies(Array.new)
|
44
|
+
}.should raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# The regexen are required because Hashes aren't ordered, so a test against
|
50
|
+
# a hardcoded string was randomly failing.
|
51
|
+
describe "#to_cookie_string" do
|
52
|
+
before(:each) do
|
53
|
+
@cookie_hash.add_cookies(:foo => "bar")
|
54
|
+
@cookie_hash.add_cookies(:rofl => "copter")
|
55
|
+
@s = @cookie_hash.to_cookie_string
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should format the key/value pairs, delimited by semi-colons" do
|
59
|
+
@s.should match(/foo=bar/)
|
60
|
+
@s.should match(/rofl=copter/)
|
61
|
+
@s.should match(/^\w+=\w+; \w+=\w+$/)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should not include client side only cookies" do
|
65
|
+
@cookie_hash.add_cookies(:path => "/")
|
66
|
+
@s = @cookie_hash.to_cookie_string
|
67
|
+
@s.should_not match(/path=\//)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
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
|
+
digest.stub(:random).and_return("deadbeef")
|
8
|
+
Digest::MD5.stub(:hexdigest) { |str| "md5(#{str})" }
|
9
|
+
digest
|
10
|
+
end
|
11
|
+
|
12
|
+
def authorization_header
|
13
|
+
@digest.authorization_header.join(", ")
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
context "with an opaque value in the response header" do
|
18
|
+
before do
|
19
|
+
@digest = setup_digest({
|
20
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com", opaque="solid"'
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should set opaque" do
|
25
|
+
authorization_header.should include(%Q(opaque="solid"))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "without an opaque valid in the response header" do
|
30
|
+
before do
|
31
|
+
@digest = setup_digest({
|
32
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com"'
|
33
|
+
})
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not set opaque" do
|
37
|
+
authorization_header.should_not include(%Q(opaque=))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with specified quality of protection (qop)" do
|
42
|
+
before do
|
43
|
+
@digest = setup_digest({
|
44
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"',
|
45
|
+
})
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should set prefix" do
|
49
|
+
authorization_header.should =~ /^Digest /
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should set username" do
|
53
|
+
authorization_header.should include(%Q(username="Mufasa"))
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should set digest-uri" do
|
57
|
+
authorization_header.should include(%Q(uri="/dir/index.html"))
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should set qop" do
|
61
|
+
authorization_header.should include(%Q(qop="auth"))
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should set cnonce" do
|
65
|
+
authorization_header.should include(%Q(cnonce="md5(deadbeef)"))
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should set nonce-count" do
|
69
|
+
authorization_header.should include(%Q(nc="00000001"))
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should set response" do
|
73
|
+
request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
|
74
|
+
authorization_header.should include(%Q(response="#{request_digest}"))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
context "with unspecified quality of protection (qop)" do
|
80
|
+
before do
|
81
|
+
@digest = setup_digest({
|
82
|
+
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE"',
|
83
|
+
})
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should set prefix" do
|
87
|
+
authorization_header.should =~ /^Digest /
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should set username" do
|
91
|
+
authorization_header.should include(%Q(username="Mufasa"))
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should set digest-uri" do
|
95
|
+
authorization_header.should include(%Q(uri="/dir/index.html"))
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should not set qop" do
|
99
|
+
authorization_header.should_not include(%Q(qop=))
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should not set cnonce" do
|
103
|
+
authorization_header.should_not include(%Q(cnonce=))
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should not set nonce-count" do
|
107
|
+
authorization_header.should_not include(%Q(nc=))
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should set response" do
|
111
|
+
request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(GET:/dir/index.html))"
|
112
|
+
authorization_header.should include(%Q(response="#{request_digest}"))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe HTTParty::Parser do
|
4
|
+
describe ".SupportedFormats" do
|
5
|
+
it "returns a hash" do
|
6
|
+
HTTParty::Parser::SupportedFormats.should 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
|
+
HTTParty::Parser.should_receive(:new).with('body', :plain).and_return(stub(:parse => nil))
|
13
|
+
HTTParty::Parser.call('body', :plain)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "calls #parse on the parser" do
|
17
|
+
parser = mock('Parser')
|
18
|
+
parser.should_receive(:parse)
|
19
|
+
HTTParty::Parser.stub(: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
|
+
HTTParty::Parser.formats.should == 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
|
+
MyParser.formats.should == {"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
|
+
HTTParty::Parser.format_from_mimetype("text/plain").should == :plain
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns nil when the mimetype is not supported" do
|
43
|
+
HTTParty::Parser.format_from_mimetype("application/atom+xml").should 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
|
+
HTTParty::Parser.supported_formats.should == 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
|
+
HTTParty::Parser.stub(:supported_formats => [:json])
|
56
|
+
HTTParty::Parser.supports_format?(:json).should be_true
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns false for an unsupported format" do
|
60
|
+
HTTParty::Parser.stub(:supported_formats => [])
|
61
|
+
HTTParty::Parser.supports_format?(:json).should be_false
|
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
|
+
@parser.stub(:supports_format? => true)
|
72
|
+
@parser.should_receive(:parse_supported_format)
|
73
|
+
@parser.parse
|
74
|
+
end
|
75
|
+
|
76
|
+
it "returns the unparsed body when the format is unsupported" do
|
77
|
+
@parser.stub(:supports_format? => false)
|
78
|
+
@parser.parse.should == @parser.body
|
79
|
+
end
|
80
|
+
|
81
|
+
it "returns nil for an empty body" do
|
82
|
+
@parser.stub(:body => '')
|
83
|
+
@parser.parse.should be_nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns nil for a nil body" do
|
87
|
+
@parser.stub(:body => nil)
|
88
|
+
@parser.parse.should be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
it "returns nil for a 'null' body" do
|
92
|
+
@parser.stub(:body => "null")
|
93
|
+
@parser.parse.should be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns nil for a body with spaces only" do
|
97
|
+
@parser.stub(:body => " ")
|
98
|
+
@parser.parse.should be_nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#supports_format?" do
|
103
|
+
it "utilizes the class method to determine if the format is supported" do
|
104
|
+
HTTParty::Parser.should_receive(:supports_format?).with(:json)
|
105
|
+
parser = HTTParty::Parser.new('body', :json)
|
106
|
+
parser.send(:supports_format?)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#parse_supported_format" do
|
111
|
+
it "calls the parser for the given format" do
|
112
|
+
parser = HTTParty::Parser.new('body', :json)
|
113
|
+
parser.should_receive(:json)
|
114
|
+
parser.send(:parse_supported_format)
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when a parsing method does not exist for the given format" do
|
118
|
+
it "raises an exception" do
|
119
|
+
parser = HTTParty::Parser.new('body', :atom)
|
120
|
+
expect do
|
121
|
+
parser.send(:parse_supported_format)
|
122
|
+
end.to raise_error(NotImplementedError, "HTTParty::Parser has not implemented a parsing method for the :atom format.")
|
123
|
+
end
|
124
|
+
|
125
|
+
it "raises a useful exception message for subclasses" do
|
126
|
+
atom_parser = Class.new(HTTParty::Parser) do
|
127
|
+
def self.name; 'AtomParser'; end
|
128
|
+
end
|
129
|
+
parser = atom_parser.new 'body', :atom
|
130
|
+
expect do
|
131
|
+
parser.send(:parse_supported_format)
|
132
|
+
end.to raise_error(NotImplementedError, "AtomParser has not implemented a parsing method for the :atom format.")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "parsers" do
|
138
|
+
subject do
|
139
|
+
HTTParty::Parser.new('body', nil)
|
140
|
+
end
|
141
|
+
|
142
|
+
it "parses xml with MultiXml" do
|
143
|
+
MultiXml.should_receive(:parse).with('body')
|
144
|
+
subject.send(:xml)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "parses json with MultiJson" do
|
148
|
+
MultiJson.should_receive(:load).with('body')
|
149
|
+
subject.send(:json)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "uses MultiJson.decode if MultiJson does not respond to adapter" do
|
153
|
+
MultiJson.should_receive(:respond_to?).with(:adapter).and_return(false)
|
154
|
+
MultiJson.should_receive(:decode).with('body')
|
155
|
+
subject.send(:json)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "parses yaml" do
|
159
|
+
YAML.should_receive(:load).with('body')
|
160
|
+
subject.send(:yaml)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "parses html by simply returning the body" do
|
164
|
+
subject.send(:html).should == 'body'
|
165
|
+
end
|
166
|
+
|
167
|
+
it "parses plain text by simply returning the body" do
|
168
|
+
subject.send(:plain).should == 'body'
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|