nullstyle-httparty 0.4.4

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 (48) hide show
  1. data/History +131 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Manifest +47 -0
  4. data/README.rdoc +54 -0
  5. data/Rakefile +48 -0
  6. data/bin/httparty +98 -0
  7. data/cucumber.yml +1 -0
  8. data/examples/aaws.rb +32 -0
  9. data/examples/basic.rb +11 -0
  10. data/examples/delicious.rb +37 -0
  11. data/examples/google.rb +16 -0
  12. data/examples/rubyurl.rb +14 -0
  13. data/examples/twitter.rb +31 -0
  14. data/examples/whoismyrep.rb +10 -0
  15. data/features/basic_authentication.feature +20 -0
  16. data/features/command_line.feature +7 -0
  17. data/features/deals_with_http_error_codes.feature +26 -0
  18. data/features/handles_multiple_formats.feature +34 -0
  19. data/features/steps/env.rb +15 -0
  20. data/features/steps/httparty_response_steps.rb +26 -0
  21. data/features/steps/httparty_steps.rb +15 -0
  22. data/features/steps/mongrel_helper.rb +55 -0
  23. data/features/steps/remote_service_steps.rb +47 -0
  24. data/features/supports_redirection.feature +22 -0
  25. data/httparty.gemspec +40 -0
  26. data/lib/httparty.rb +213 -0
  27. data/lib/httparty/cookie_hash.rb +9 -0
  28. data/lib/httparty/core_extensions.rb +29 -0
  29. data/lib/httparty/exceptions.rb +7 -0
  30. data/lib/httparty/module_inheritable_attributes.rb +25 -0
  31. data/lib/httparty/request.rb +141 -0
  32. data/lib/httparty/response.rb +18 -0
  33. data/lib/httparty/version.rb +3 -0
  34. data/spec/fixtures/delicious.xml +23 -0
  35. data/spec/fixtures/empty.xml +0 -0
  36. data/spec/fixtures/google.html +3 -0
  37. data/spec/fixtures/twitter.json +1 -0
  38. data/spec/fixtures/twitter.xml +403 -0
  39. data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
  40. data/spec/httparty/cookie_hash_spec.rb +38 -0
  41. data/spec/httparty/request_spec.rb +199 -0
  42. data/spec/httparty/response_spec.rb +62 -0
  43. data/spec/httparty_spec.rb +300 -0
  44. data/spec/spec.opts +3 -0
  45. data/spec/spec_helper.rb +21 -0
  46. data/website/css/common.css +47 -0
  47. data/website/index.html +74 -0
  48. metadata +133 -0
@@ -0,0 +1,2 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Entities total="0" results="0" page="1" page-size="25" href="https://s3-sandbox.parature.com/api/v1/5578/5633/Account" />
@@ -0,0 +1,38 @@
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
+ it "should add new key/value pairs to the hash" do
10
+ @cookie_hash.add_cookies(:foo => "bar")
11
+ @cookie_hash.add_cookies(:rofl => "copter")
12
+ @cookie_hash.length.should eql(2)
13
+ end
14
+
15
+ it "should overwrite any existing key" do
16
+ @cookie_hash.add_cookies(:foo => "bar")
17
+ @cookie_hash.add_cookies(:foo => "copter")
18
+ @cookie_hash.length.should eql(1)
19
+ @cookie_hash[:foo].should eql("copter")
20
+ end
21
+ end
22
+
23
+ # The regexen are required because Hashes aren't ordered, so a test against
24
+ # a hardcoded string was randomly failing.
25
+ describe "#to_cookie_string" do
26
+ before(:each) do
27
+ @cookie_hash.add_cookies(:foo => "bar")
28
+ @cookie_hash.add_cookies(:rofl => "copter")
29
+ @s = @cookie_hash.to_cookie_string
30
+ end
31
+
32
+ it "should format the key/value pairs, delimited by semi-colons" do
33
+ @s.should match(/foo=bar/)
34
+ @s.should match(/rofl=copter/)
35
+ @s.should match(/^\w+=\w+; \w+=\w+$/)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,199 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe HTTParty::Request do
4
+ def stub_response(body, code = 200)
5
+ unless @http
6
+ @http = Net::HTTP.new('localhost', 80)
7
+ @request.stub!(:http).and_return(@http)
8
+ @request.stub!(:uri).and_return(URI.parse("http://foo.com/foobar"))
9
+ end
10
+
11
+ response = Net::HTTPResponse::CODE_TO_OBJ[code.to_s].new("1.1", code, body)
12
+ response.stub!(:body).and_return(body)
13
+
14
+ @http.stub!(:request).and_return(response)
15
+ response
16
+ end
17
+
18
+ before do
19
+ @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml)
20
+ end
21
+
22
+ describe "#format" do
23
+ it "should return the correct parsing format" do
24
+ @request.format.should == :xml
25
+ end
26
+ end
27
+
28
+ describe 'http' do
29
+ it "should use ssl for port 443" do
30
+ request = HTTParty::Request.new(Net::HTTP::Get, 'https://api.foo.com/v1:443')
31
+ request.send(:http).use_ssl?.should == true
32
+ end
33
+
34
+ it 'should not use ssl for port 80' do
35
+ request = HTTParty::Request.new(Net::HTTP::Get, 'http://foobar.com')
36
+ request.send(:http).use_ssl?.should == false
37
+ end
38
+
39
+ it "should use ssl for https scheme" do
40
+ request = HTTParty::Request.new(Net::HTTP::Get, 'https://foobar.com')
41
+ request.send(:http).use_ssl?.should == true
42
+ end
43
+
44
+ it "should use basic auth when configured" do
45
+ @request.options[:basic_auth] = {:username => 'foobar', :password => 'secret'}
46
+ @request.send(:setup_raw_request)
47
+ @request.instance_variable_get(:@raw_request)['authorization'].should_not be_nil
48
+ end
49
+ end
50
+
51
+ describe '#format_from_mimetype' do
52
+ it 'should handle text/xml' do
53
+ ["text/xml", "text/xml; charset=iso8859-1"].each do |ct|
54
+ @request.send(:format_from_mimetype, ct).should == :xml
55
+ end
56
+ end
57
+
58
+ it 'should handle application/xml' do
59
+ ["application/xml", "application/xml; charset=iso8859-1"].each do |ct|
60
+ @request.send(:format_from_mimetype, ct).should == :xml
61
+ end
62
+ end
63
+
64
+ it 'should handle text/json' do
65
+ ["text/json", "text/json; charset=iso8859-1"].each do |ct|
66
+ @request.send(:format_from_mimetype, ct).should == :json
67
+ end
68
+ end
69
+
70
+ it 'should handle application/json' do
71
+ ["application/json", "application/json; charset=iso8859-1"].each do |ct|
72
+ @request.send(:format_from_mimetype, ct).should == :json
73
+ end
74
+ end
75
+
76
+ it 'should handle text/javascript' do
77
+ ["text/javascript", "text/javascript; charset=iso8859-1"].each do |ct|
78
+ @request.send(:format_from_mimetype, ct).should == :json
79
+ end
80
+ end
81
+
82
+ it 'should handle application/javascript' do
83
+ ["application/javascript", "application/javascript; charset=iso8859-1"].each do |ct|
84
+ @request.send(:format_from_mimetype, ct).should == :json
85
+ end
86
+ end
87
+ end
88
+
89
+ describe 'parsing responses' do
90
+ it 'should handle xml automatically' do
91
+ xml = %q[<books><book><id>1234</id><name>Foo Bar!</name></book></books>]
92
+ @request.options[:format] = :xml
93
+ @request.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
94
+ end
95
+
96
+ it 'should handle json automatically' do
97
+ json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}]
98
+ @request.options[:format] = :json
99
+ @request.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
100
+ end
101
+
102
+ it 'should handle yaml automatically' do
103
+ yaml = "books: \n book: \n name: Foo Bar!\n id: \"1234\"\n"
104
+ @request.options[:format] = :yaml
105
+ @request.send(:parse_response, yaml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
106
+ end
107
+
108
+ it "should include any HTTP headers in the returned response" do
109
+ @request.options[:format] = :html
110
+ response = stub_response "Content"
111
+ response.initialize_http_header("key" => "value")
112
+
113
+ @request.perform.headers.should == { "key" => ["value"] }
114
+ end
115
+
116
+ describe 'with non-200 responses' do
117
+ it 'should return a valid object for 4xx response' do
118
+ stub_response '<foo><bar>yes</bar></foo>', 401
119
+ resp = @request.perform
120
+ resp.code.should == 401
121
+ resp.body.should == "<foo><bar>yes</bar></foo>"
122
+ resp['foo']['bar'].should == "yes"
123
+ end
124
+
125
+ it 'should return a valid object for 5xx response' do
126
+ stub_response '<foo><bar>error</bar></foo>', 500
127
+ resp = @request.perform
128
+ resp.code.should == 500
129
+ resp.body.should == "<foo><bar>error</bar></foo>"
130
+ resp['foo']['bar'].should == "error"
131
+ end
132
+ end
133
+ end
134
+
135
+ it "should not attempt to parse empty responses" do
136
+ stub_response "", 204
137
+
138
+ @request.options[:format] = :xml
139
+ @request.perform.should be_nil
140
+ end
141
+
142
+ it "should not fail for missing mime type" do
143
+ stub_response "Content for you"
144
+ @request.options[:format] = :html
145
+ @request.perform.should == 'Content for you'
146
+ end
147
+
148
+ describe "a request that redirects" do
149
+ before(:each) do
150
+ @redirect = stub_response("", 302)
151
+ @redirect['location'] = '/foo'
152
+
153
+ @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
154
+ end
155
+
156
+ describe "once" do
157
+ before(:each) do
158
+ @http.stub!(:request).and_return(@redirect, @ok)
159
+ end
160
+
161
+ it "should be handled by GET transparently" do
162
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
163
+ end
164
+
165
+ it "should be handled by POST transparently" do
166
+ @request.http_method = Net::HTTP::Post
167
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
168
+ end
169
+
170
+ it "should be handled by DELETE transparently" do
171
+ @request.http_method = Net::HTTP::Delete
172
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
173
+ end
174
+
175
+ it "should be handled by PUT transparently" do
176
+ @request.http_method = Net::HTTP::Put
177
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
178
+ end
179
+ end
180
+
181
+ describe "infinitely" do
182
+ before(:each) do
183
+ @http.stub!(:request).and_return(@redirect)
184
+ end
185
+
186
+ it "should raise an exception" do
187
+ lambda { @request.perform }.should raise_error(HTTParty::RedirectionTooDeep)
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ describe HTTParty::Request, "with POST http method" do
194
+ it "should raise argument error if query is not a hash" do
195
+ lambda {
196
+ HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :format => :xml, :query => 'astring').perform
197
+ }.should raise_error(ArgumentError)
198
+ end
199
+ end
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe HTTParty::Response do
4
+ describe "initialization" do
5
+ before do
6
+ @response_object = {'foo' => 'bar'}
7
+ @body = "{foo:'bar'}"
8
+ @code = '200'
9
+ @message = 'OK'
10
+ @response = HTTParty::Response.new(@response_object, @body, @code, @message)
11
+ end
12
+
13
+ it "should set delegate" do
14
+ @response.delegate.should == @response_object
15
+ end
16
+
17
+ it "should set body" do
18
+ @response.body.should == @body
19
+ end
20
+
21
+ it "should set code" do
22
+ @response.code.should.to_s == @code
23
+ end
24
+
25
+ it "should set code as a Fixnum" do
26
+ @response.code.should be_an_instance_of(Fixnum)
27
+ end
28
+
29
+ it "should set body" do
30
+ @response.body.should == @body
31
+ end
32
+ end
33
+
34
+ it "should be able to set headers during initialization" do
35
+ response = HTTParty::Response.new({'foo' => 'bar'}, "{foo:'bar'}", 200, 'OK', {'foo' => 'bar'})
36
+ response.headers.should == {'foo' => 'bar'}
37
+ end
38
+
39
+ it "should send missing methods to delegate" do
40
+ response = HTTParty::Response.new({'foo' => 'bar'}, "{foo:'bar'}", 200, 'OK')
41
+ response['foo'].should == 'bar'
42
+ end
43
+
44
+ it "should be able to iterate delegate if it is array" do
45
+ response = HTTParty::Response.new([{'foo' => 'bar'}, {'foo' => 'baz'}], "[{foo:'bar'}, {foo:'baz'}]", 200, 'OK')
46
+ response.size.should == 2
47
+ lambda {
48
+ response.each { |item| }
49
+ }.should_not raise_error
50
+ end
51
+
52
+ xit "should allow hashes to be accessed with dot notation" do
53
+ response = HTTParty::Response.new({'foo' => 'bar'}, "{foo:'bar'}", 200, 'OK')
54
+ response.foo.should == 'bar'
55
+ end
56
+
57
+ xit "should allow nested hashes to be accessed with dot notation" do
58
+ response = HTTParty::Response.new({'foo' => {'bar' => 'baz'}}, "{foo: {bar:'baz'}}", 200, 'OK')
59
+ response.foo.should == {'bar' => 'baz'}
60
+ response.foo.bar.should == 'baz'
61
+ end
62
+ end
@@ -0,0 +1,300 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ describe HTTParty do
4
+ before(:each) do
5
+ @klass = Class.new
6
+ @klass.instance_eval { include HTTParty }
7
+ end
8
+
9
+ describe "base uri" do
10
+ before(:each) do
11
+ @klass.base_uri('api.foo.com/v1')
12
+ end
13
+
14
+ it "should have reader" do
15
+ @klass.base_uri.should == 'http://api.foo.com/v1'
16
+ end
17
+
18
+ it 'should have writer' do
19
+ @klass.base_uri('http://api.foobar.com')
20
+ @klass.base_uri.should == 'http://api.foobar.com'
21
+ end
22
+
23
+ it 'should not modify the parameter during assignment' do
24
+ uri = 'http://api.foobar.com'
25
+ @klass.base_uri(uri)
26
+ uri.should == 'http://api.foobar.com'
27
+ end
28
+ end
29
+
30
+ describe "#normalize_base_uri" do
31
+ it "should add http if not present for non ssl requests" do
32
+ uri = HTTParty.normalize_base_uri('api.foobar.com')
33
+ uri.should == 'http://api.foobar.com'
34
+ end
35
+
36
+ it "should add https if not present for ssl requests" do
37
+ uri = HTTParty.normalize_base_uri('api.foo.com/v1:443')
38
+ uri.should == 'https://api.foo.com/v1:443'
39
+ end
40
+
41
+ it "should not remove https for ssl requests" do
42
+ uri = HTTParty.normalize_base_uri('https://api.foo.com/v1:443')
43
+ uri.should == 'https://api.foo.com/v1:443'
44
+ end
45
+
46
+ it 'should not modify the parameter' do
47
+ uri = 'http://api.foobar.com'
48
+ HTTParty.normalize_base_uri(uri)
49
+ uri.should == 'http://api.foobar.com'
50
+ end
51
+ end
52
+
53
+ describe "headers" do
54
+ it "should default to empty hash" do
55
+ @klass.headers.should == {}
56
+ end
57
+
58
+ it "should be able to be updated" do
59
+ init_headers = {:foo => 'bar', :baz => 'spax'}
60
+ @klass.headers init_headers
61
+ @klass.headers.should == init_headers
62
+ end
63
+
64
+ it "should be merged with passed in headers" do
65
+ init_headers = {"foo" => 'bar'}
66
+ @klass.headers init_headers
67
+ HTTParty::Request.should_receive(:new) \
68
+ .with(anything, anything, hash_including({ :headers => {"foo" => 'bar', "baz" => 'spax', "cookie" => ""} })) \
69
+ .and_return(mock("mock response", :perform => nil))
70
+
71
+ @klass.get("", :headers => {"baz" => 'spax'})
72
+ end
73
+ end
74
+
75
+ describe "cookies" do
76
+ def expect_cookie_header(s)
77
+ HTTParty::Request.should_receive(:new) \
78
+ .with(anything, anything, hash_including({ :headers => { "cookie" => s } })) \
79
+ .and_return(mock("mock response", :perform => nil))
80
+ end
81
+
82
+ it "should not be in the headers by default" do
83
+ HTTParty::Request.stub!(:new).and_return(stub(nil, :perform => nil))
84
+ @klass.get("")
85
+ @klass.headers.keys.should_not include("cookie")
86
+ end
87
+
88
+ it "should raise an ArgumentError if passed a non-Hash" do
89
+ lambda do
90
+ @klass.cookies("nonsense")
91
+ end.should raise_error(ArgumentError)
92
+ end
93
+
94
+ it "should allow a cookie to be specified with a one-off request" do
95
+ expect_cookie_header "type=snickerdoodle"
96
+ @klass.get("", :cookies => { :type => "snickerdoodle" })
97
+ end
98
+
99
+ describe "when a cookie is set at the class level" do
100
+ before(:each) do
101
+ @klass.cookies({ :type => "snickerdoodle" })
102
+ end
103
+
104
+ it "should include that cookie in the request" do
105
+ expect_cookie_header "type=snickerdoodle"
106
+ @klass.get("")
107
+ end
108
+
109
+ it "should pass the proper cookies when requested multiple times" do
110
+ 2.times do
111
+ expect_cookie_header "type=snickerdoodle"
112
+ @klass.get("")
113
+ end
114
+ end
115
+
116
+ it "should allow the class defaults to be overridden" do
117
+ expect_cookie_header "type=chocolate_chip"
118
+
119
+ @klass.get("", :cookies => { :type => "chocolate_chip" })
120
+ end
121
+ end
122
+
123
+ describe "in a class with multiple methods that use different cookies" do
124
+ before(:each) do
125
+ @klass.instance_eval do
126
+ def first_method
127
+ get("first_method", :cookies => { :first_method_cookie => "foo" })
128
+ end
129
+
130
+ def second_method
131
+ get("second_method", :cookies => { :second_method_cookie => "foo" })
132
+ end
133
+ end
134
+ end
135
+
136
+ it "should not allow cookies used in one method to carry over into other methods" do
137
+ expect_cookie_header "first_method_cookie=foo"
138
+ @klass.first_method
139
+
140
+ expect_cookie_header "second_method_cookie=foo"
141
+ @klass.second_method
142
+ end
143
+ end
144
+ end
145
+
146
+ describe "default params" do
147
+ it "should default to empty hash" do
148
+ @klass.default_params.should == {}
149
+ end
150
+
151
+ it "should be able to be updated" do
152
+ new_defaults = {:foo => 'bar', :baz => 'spax'}
153
+ @klass.default_params new_defaults
154
+ @klass.default_params.should == new_defaults
155
+ end
156
+ end
157
+
158
+ describe "basic http authentication" do
159
+ it "should work" do
160
+ @klass.basic_auth 'foobar', 'secret'
161
+ @klass.default_options[:basic_auth].should == {:username => 'foobar', :password => 'secret'}
162
+ end
163
+ end
164
+
165
+ describe "format" do
166
+ it "should allow xml" do
167
+ @klass.format :xml
168
+ @klass.default_options[:format].should == :xml
169
+ end
170
+
171
+ it "should allow json" do
172
+ @klass.format :json
173
+ @klass.default_options[:format].should == :json
174
+ end
175
+
176
+ it "should allow yaml" do
177
+ @klass.format :yaml
178
+ @klass.default_options[:format].should == :yaml
179
+ end
180
+
181
+ it "should allow plain" do
182
+ @klass.format :plain
183
+ @klass.default_options[:format].should == :plain
184
+ end
185
+
186
+ it 'should not allow funky format' do
187
+ lambda do
188
+ @klass.format :foobar
189
+ end.should raise_error(HTTParty::UnsupportedFormat)
190
+ end
191
+
192
+ it 'should only print each format once with an exception' do
193
+ lambda do
194
+ @klass.format :foobar
195
+ end.should raise_error(HTTParty::UnsupportedFormat, "Must be one of: html, json, plain, xml, yaml")
196
+ end
197
+
198
+ end
199
+
200
+ describe "with explicit override of automatic redirect handling" do
201
+
202
+ it "should fail with redirected GET" do
203
+ lambda do
204
+ @klass.get('/foo', :no_follow => true)
205
+ end.should raise_error(HTTParty::RedirectionTooDeep)
206
+ end
207
+
208
+ it "should fail with redirected POST" do
209
+ lambda do
210
+ @klass.post('/foo', :no_follow => true)
211
+ end.should raise_error(HTTParty::RedirectionTooDeep)
212
+ end
213
+
214
+ it "should fail with redirected DELETE" do
215
+ lambda do
216
+ @klass.delete('/foo', :no_follow => true)
217
+ end.should raise_error(HTTParty::RedirectionTooDeep)
218
+ end
219
+
220
+ it "should fail with redirected PUT" do
221
+ lambda do
222
+ @klass.put('/foo', :no_follow => true)
223
+ end.should raise_error(HTTParty::RedirectionTooDeep)
224
+ end
225
+ end
226
+
227
+ describe "with multiple class definitions" do
228
+ before(:each) do
229
+ @klass.instance_eval do
230
+ base_uri "http://first.com"
231
+ default_params :one => 1
232
+ end
233
+
234
+ @additional_klass = Class.new
235
+ @additional_klass.instance_eval do
236
+ include HTTParty
237
+ base_uri "http://second.com"
238
+ default_params :two => 2
239
+ end
240
+ end
241
+
242
+ it "should not run over each others options" do
243
+ @klass.default_options.should == { :base_uri => 'http://first.com', :default_params => { :one => 1 } }
244
+ @additional_klass.default_options.should == { :base_uri => 'http://second.com', :default_params => { :two => 2 } }
245
+ end
246
+ end
247
+
248
+ describe "#get" do
249
+ it "should be able to get html" do
250
+ stub_http_response_with('google.html')
251
+ HTTParty.get('http://www.google.com').should == file_fixture('google.html')
252
+ end
253
+
254
+ it "should be able parse response type json automatically" do
255
+ stub_http_response_with('twitter.json')
256
+ tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
257
+ tweets.size.should == 20
258
+ tweets.first['user'].should == {
259
+ "name" => "Pyk",
260
+ "url" => nil,
261
+ "id" => "7694602",
262
+ "description" => nil,
263
+ "protected" => false,
264
+ "screen_name" => "Pyk",
265
+ "followers_count" => 1,
266
+ "location" => "Opera Plaza, California",
267
+ "profile_image_url" => "http://static.twitter.com/images/default_profile_normal.png"
268
+ }
269
+ end
270
+
271
+ it "should be able parse response type xml automatically" do
272
+ stub_http_response_with('twitter.xml')
273
+ tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.xml')
274
+ tweets['statuses'].size.should == 20
275
+ tweets['statuses'].first['user'].should == {
276
+ "name" => "Magic 8 Bot",
277
+ "url" => nil,
278
+ "id" => "17656026",
279
+ "description" => "ask me a question",
280
+ "protected" => "false",
281
+ "screen_name" => "magic8bot",
282
+ "followers_count" => "90",
283
+ "profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",
284
+ "location" => nil
285
+ }
286
+ end
287
+
288
+ it "should not get undefined method add_node for nil class for the following xml" do
289
+ stub_http_response_with('undefined_method_add_node_for_nil.xml')
290
+ result = HTTParty.get('http://foobar.com')
291
+ result.should == {"Entities"=>{"href"=>"https://s3-sandbox.parature.com/api/v1/5578/5633/Account", "results"=>"0", "total"=>"0", "page_size"=>"25", "page"=>"1"}}
292
+ end
293
+
294
+ it "should parse empty response fine" do
295
+ stub_http_response_with('empty.xml')
296
+ result = HTTParty.get('http://foobar.com')
297
+ result.should == nil
298
+ end
299
+ end
300
+ end