voxdolo-httparty 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/History +108 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Manifest +55 -0
  4. data/README +35 -0
  5. data/Rakefile +47 -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 +37 -0
  26. data/lib/core_extensions.rb +175 -0
  27. data/lib/httparty/cookie_hash.rb +9 -0
  28. data/lib/httparty/exceptions.rb +7 -0
  29. data/lib/httparty/module_inheritable_attributes.rb +25 -0
  30. data/lib/httparty/parsers/json.rb +74 -0
  31. data/lib/httparty/parsers/xml.rb +209 -0
  32. data/lib/httparty/parsers.rb +4 -0
  33. data/lib/httparty/request.rb +139 -0
  34. data/lib/httparty/response.rb +17 -0
  35. data/lib/httparty/version.rb +3 -0
  36. data/lib/httparty.rb +201 -0
  37. data/setup.rb +1585 -0
  38. data/spec/fixtures/delicious.xml +23 -0
  39. data/spec/fixtures/empty.xml +0 -0
  40. data/spec/fixtures/google.html +3 -0
  41. data/spec/fixtures/twitter.json +1 -0
  42. data/spec/fixtures/twitter.xml +403 -0
  43. data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
  44. data/spec/hash_spec.rb +49 -0
  45. data/spec/httparty/cookie_hash_spec.rb +38 -0
  46. data/spec/httparty/parsers/json_spec.rb +42 -0
  47. data/spec/httparty/parsers/xml_spec.rb +445 -0
  48. data/spec/httparty/request_spec.rb +205 -0
  49. data/spec/httparty/response_spec.rb +53 -0
  50. data/spec/httparty_spec.rb +259 -0
  51. data/spec/spec.opts +3 -0
  52. data/spec/spec_helper.rb +21 -0
  53. data/spec/string_spec.rb +27 -0
  54. data/website/css/common.css +47 -0
  55. data/website/index.html +74 -0
  56. metadata +133 -0
@@ -0,0 +1,42 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
+
3
+ describe HTTParty::Parsers::JSON do
4
+ TESTS = {
5
+ %q({"data": "G\u00fcnter"}) => {"data" => "Günter"},
6
+ %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
7
+ %q({returnTo:{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
8
+ %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}},
9
+ %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}},
10
+ %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]},
11
+ %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]},
12
+ %({a: "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"},
13
+ %({a: "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"},
14
+ %({a: "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)},
15
+ %({a: "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)},
16
+ # no time zone
17
+ %({a: "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"},
18
+ %([]) => [],
19
+ %({}) => {},
20
+ %(1) => 1,
21
+ %("") => "",
22
+ %("\\"") => "\"",
23
+ %(null) => nil,
24
+ %(true) => true,
25
+ %(false) => false,
26
+ %q("http:\/\/test.host\/posts\/1") => "http://test.host/posts/1"
27
+ }
28
+
29
+ TESTS.each do |json, expected|
30
+ it "should decode json (#{json})" do
31
+ lambda {
32
+ HTTParty::Parsers::JSON.decode(json).should == expected
33
+ }.should_not raise_error
34
+ end
35
+ end
36
+
37
+ it "should raise error for failed decoding" do
38
+ lambda {
39
+ HTTParty::Parsers::JSON.decode(%({: 1}))
40
+ }.should raise_error(HTTParty::Parsers::JSON::ParseError)
41
+ end
42
+ end
@@ -0,0 +1,445 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
+
3
+ require "date"
4
+ require 'bigdecimal'
5
+
6
+ describe HTTParty::Parsers::XML, "#parse" do
7
+ it "should transform a simple tag with content" do
8
+ xml = "<tag>This is the contents</tag>"
9
+ HTTParty::Parsers::XML.parse(xml).should == { 'tag' => 'This is the contents' }
10
+ end
11
+
12
+ it "should work with cdata tags" do
13
+ xml = <<-END
14
+ <tag>
15
+ <![CDATA[
16
+ text inside cdata
17
+ ]]>
18
+ </tag>
19
+ END
20
+ HTTParty::Parsers::XML.parse(xml)["tag"].strip.should == "text inside cdata"
21
+ end
22
+
23
+ it "should transform a simple tag with attributes" do
24
+ xml = "<tag attr1='1' attr2='2'></tag>"
25
+ hash = { 'tag' => { 'attr1' => '1', 'attr2' => '2' } }
26
+ HTTParty::Parsers::XML.parse(xml).should == hash
27
+ end
28
+
29
+ it "should transform repeating siblings into an array" do
30
+ xml =<<-XML
31
+ <opt>
32
+ <user login="grep" fullname="Gary R Epstein" />
33
+ <user login="stty" fullname="Simon T Tyson" />
34
+ </opt>
35
+ XML
36
+
37
+ HTTParty::Parsers::XML.parse(xml)['opt']['user'].should be_an_instance_of(Array)
38
+
39
+ hash = {
40
+ 'opt' => {
41
+ 'user' => [{
42
+ 'login' => 'grep',
43
+ 'fullname' => 'Gary R Epstein'
44
+ },{
45
+ 'login' => 'stty',
46
+ 'fullname' => 'Simon T Tyson'
47
+ }]
48
+ }
49
+ }
50
+
51
+ HTTParty::Parsers::XML.parse(xml).should == hash
52
+ end
53
+
54
+ it "should not transform non-repeating siblings into an array" do
55
+ xml =<<-XML
56
+ <opt>
57
+ <user login="grep" fullname="Gary R Epstein" />
58
+ </opt>
59
+ XML
60
+
61
+ HTTParty::Parsers::XML.parse(xml)['opt']['user'].should be_an_instance_of(Hash)
62
+
63
+ hash = {
64
+ 'opt' => {
65
+ 'user' => {
66
+ 'login' => 'grep',
67
+ 'fullname' => 'Gary R Epstein'
68
+ }
69
+ }
70
+ }
71
+
72
+ HTTParty::Parsers::XML.parse(xml).should == hash
73
+ end
74
+
75
+ it "should typecast an integer" do
76
+ xml = "<tag type='integer'>10</tag>"
77
+ HTTParty::Parsers::XML.parse(xml)['tag'].should == 10
78
+ end
79
+
80
+ it "should typecast a true boolean" do
81
+ xml = "<tag type='boolean'>true</tag>"
82
+ HTTParty::Parsers::XML.parse(xml)['tag'].should be_true
83
+ end
84
+
85
+ it "should typecast a false boolean" do
86
+ ["false"].each do |w|
87
+ HTTParty::Parsers::XML.parse("<tag type='boolean'>#{w}</tag>")['tag'].should be_false
88
+ end
89
+ end
90
+
91
+ it "should typecast a datetime" do
92
+ xml = "<tag type='datetime'>2007-12-31 10:32</tag>"
93
+ HTTParty::Parsers::XML.parse(xml)['tag'].should == Time.parse( '2007-12-31 10:32' ).utc
94
+ end
95
+
96
+ it "should typecast a date" do
97
+ xml = "<tag type='date'>2007-12-31</tag>"
98
+ HTTParty::Parsers::XML.parse(xml)['tag'].should == Date.parse('2007-12-31')
99
+ end
100
+
101
+ it "should unescape html entities" do
102
+ values = {
103
+ "<" => "&lt;",
104
+ ">" => "&gt;",
105
+ '"' => "&quot;",
106
+ "'" => "&apos;",
107
+ "&" => "&amp;"
108
+ }
109
+ values.each do |k,v|
110
+ xml = "<tag>Some content #{v}</tag>"
111
+ HTTParty::Parsers::XML.parse(xml)['tag'].should match(Regexp.new(k))
112
+ end
113
+ end
114
+
115
+ it "should undasherize keys as tags" do
116
+ xml = "<tag-1>Stuff</tag-1>"
117
+ HTTParty::Parsers::XML.parse(xml).keys.should include( 'tag_1' )
118
+ end
119
+
120
+ it "should undasherize keys as attributes" do
121
+ xml = "<tag1 attr-1='1'></tag1>"
122
+ HTTParty::Parsers::XML.parse(xml)['tag1'].keys.should include( 'attr_1')
123
+ end
124
+
125
+ it "should undasherize keys as tags and attributes" do
126
+ xml = "<tag-1 attr-1='1'></tag-1>"
127
+ HTTParty::Parsers::XML.parse(xml).keys.should include( 'tag_1' )
128
+ HTTParty::Parsers::XML.parse(xml)['tag_1'].keys.should include( 'attr_1')
129
+ end
130
+
131
+ it "should render nested content correctly" do
132
+ xml = "<root><tag1>Tag1 Content <em><strong>This is strong</strong></em></tag1></root>"
133
+ HTTParty::Parsers::XML.parse(xml)['root']['tag1'].should == "Tag1 Content <em><strong>This is strong</strong></em>"
134
+ end
135
+
136
+ it "should render nested content with split text nodes correctly" do
137
+ xml = "<root>Tag1 Content<em>Stuff</em> Hi There</root>"
138
+ HTTParty::Parsers::XML.parse(xml)['root'].should == "Tag1 Content<em>Stuff</em> Hi There"
139
+ end
140
+
141
+ it "should ignore attributes when a child is a text node" do
142
+ xml = "<root attr1='1'>Stuff</root>"
143
+ HTTParty::Parsers::XML.parse(xml).should == { "root" => "Stuff" }
144
+ end
145
+
146
+ it "should ignore attributes when any child is a text node" do
147
+ xml = "<root attr1='1'>Stuff <em>in italics</em></root>"
148
+ HTTParty::Parsers::XML.parse(xml).should == { "root" => "Stuff <em>in italics</em>" }
149
+ end
150
+
151
+ it "should correctly transform multiple children" do
152
+ xml = <<-XML
153
+ <user gender='m'>
154
+ <age type='integer'>35</age>
155
+ <name>Home Simpson</name>
156
+ <dob type='date'>1988-01-01</dob>
157
+ <joined-at type='datetime'>2000-04-28 23:01</joined-at>
158
+ <is-cool type='boolean'>true</is-cool>
159
+ </user>
160
+ XML
161
+
162
+ hash = {
163
+ "user" => {
164
+ "gender" => "m",
165
+ "age" => 35,
166
+ "name" => "Home Simpson",
167
+ "dob" => Date.parse('1988-01-01'),
168
+ "joined_at" => Time.parse("2000-04-28 23:01"),
169
+ "is_cool" => true
170
+ }
171
+ }
172
+
173
+ HTTParty::Parsers::XML.parse(xml).should == hash
174
+ end
175
+
176
+ it "should properly handle nil values (ActiveSupport Compatible)" do
177
+ topic_xml = <<-EOT
178
+ <topic>
179
+ <title></title>
180
+ <id type="integer"></id>
181
+ <approved type="boolean"></approved>
182
+ <written-on type="date"></written-on>
183
+ <viewed-at type="datetime"></viewed-at>
184
+ <content type="yaml"></content>
185
+ <parent-id></parent-id>
186
+ </topic>
187
+ EOT
188
+
189
+ expected_topic_hash = {
190
+ 'title' => nil,
191
+ 'id' => nil,
192
+ 'approved' => nil,
193
+ 'written_on' => nil,
194
+ 'viewed_at' => nil,
195
+ 'content' => nil,
196
+ 'parent_id' => nil
197
+ }
198
+ HTTParty::Parsers::XML.parse(topic_xml)["topic"].should == expected_topic_hash
199
+ end
200
+
201
+ it "should handle a single record from xml (ActiveSupport Compatible)" do
202
+ topic_xml = <<-EOT
203
+ <topic>
204
+ <title>The First Topic</title>
205
+ <author-name>David</author-name>
206
+ <id type="integer">1</id>
207
+ <approved type="boolean"> true </approved>
208
+ <replies-count type="integer">0</replies-count>
209
+ <replies-close-in type="integer">2592000000</replies-close-in>
210
+ <written-on type="date">2003-07-16</written-on>
211
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
212
+ <content type="yaml">--- \n1: should be an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</content>
213
+ <author-email-address>david@loudthinking.com</author-email-address>
214
+ <parent-id></parent-id>
215
+ <ad-revenue type="decimal">1.5</ad-revenue>
216
+ <optimum-viewing-angle type="float">135</optimum-viewing-angle>
217
+ <resident type="symbol">yes</resident>
218
+ </topic>
219
+ EOT
220
+
221
+ expected_topic_hash = {
222
+ 'title' => "The First Topic",
223
+ 'author_name' => "David",
224
+ 'id' => 1,
225
+ 'approved' => true,
226
+ 'replies_count' => 0,
227
+ 'replies_close_in' => 2592000000,
228
+ 'written_on' => Date.new(2003, 7, 16),
229
+ 'viewed_at' => Time.utc(2003, 7, 16, 9, 28),
230
+ # Changed this line where the key is :message. The yaml specifies this as a symbol, and who am I to change what you specify
231
+ # The line in ActiveSupport is
232
+ # 'content' => { 'message' => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
233
+ 'content' => { :message => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
234
+ 'author_email_address' => "david@loudthinking.com",
235
+ 'parent_id' => nil,
236
+ 'ad_revenue' => BigDecimal("1.50"),
237
+ 'optimum_viewing_angle' => 135.0,
238
+ 'resident' => :yes
239
+ }
240
+
241
+ HTTParty::Parsers::XML.parse(topic_xml)["topic"].each do |k,v|
242
+ v.should == expected_topic_hash[k]
243
+ end
244
+ end
245
+
246
+ it "should handle multiple records (ActiveSupport Compatible)" do
247
+ topics_xml = <<-EOT
248
+ <topics type="array">
249
+ <topic>
250
+ <title>The First Topic</title>
251
+ <author-name>David</author-name>
252
+ <id type="integer">1</id>
253
+ <approved type="boolean">false</approved>
254
+ <replies-count type="integer">0</replies-count>
255
+ <replies-close-in type="integer">2592000000</replies-close-in>
256
+ <written-on type="date">2003-07-16</written-on>
257
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
258
+ <content>Have a nice day</content>
259
+ <author-email-address>david@loudthinking.com</author-email-address>
260
+ <parent-id nil="true"></parent-id>
261
+ </topic>
262
+ <topic>
263
+ <title>The Second Topic</title>
264
+ <author-name>Jason</author-name>
265
+ <id type="integer">1</id>
266
+ <approved type="boolean">false</approved>
267
+ <replies-count type="integer">0</replies-count>
268
+ <replies-close-in type="integer">2592000000</replies-close-in>
269
+ <written-on type="date">2003-07-16</written-on>
270
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
271
+ <content>Have a nice day</content>
272
+ <author-email-address>david@loudthinking.com</author-email-address>
273
+ <parent-id></parent-id>
274
+ </topic>
275
+ </topics>
276
+ EOT
277
+
278
+ expected_topic_hash = {
279
+ 'title' => "The First Topic",
280
+ 'author_name' => "David",
281
+ 'id' => 1,
282
+ 'approved' => false,
283
+ 'replies_count' => 0,
284
+ 'replies_close_in' => 2592000000,
285
+ 'written_on' => Date.new(2003, 7, 16),
286
+ 'viewed_at' => Time.utc(2003, 7, 16, 9, 28),
287
+ 'content' => "Have a nice day",
288
+ 'author_email_address' => "david@loudthinking.com",
289
+ 'parent_id' => nil
290
+ }
291
+ # puts HTTParty::Parsers::XML.parse(topics_xml)['topics'].first.inspect
292
+ HTTParty::Parsers::XML.parse(topics_xml)["topics"].first.each do |k,v|
293
+ v.should == expected_topic_hash[k]
294
+ end
295
+ end
296
+
297
+ it "should handle a single record from_xml with attributes other than type (ActiveSupport Compatible)" do
298
+ topic_xml = <<-EOT
299
+ <rsp stat="ok">
300
+ <photos page="1" pages="1" perpage="100" total="16">
301
+ <photo id="175756086" owner="55569174@N00" secret="0279bf37a1" server="76" title="Colored Pencil PhotoBooth Fun" ispublic="1" isfriend="0" isfamily="0"/>
302
+ </photos>
303
+ </rsp>
304
+ EOT
305
+
306
+ expected_topic_hash = {
307
+ 'id' => "175756086",
308
+ 'owner' => "55569174@N00",
309
+ 'secret' => "0279bf37a1",
310
+ 'server' => "76",
311
+ 'title' => "Colored Pencil PhotoBooth Fun",
312
+ 'ispublic' => "1",
313
+ 'isfriend' => "0",
314
+ 'isfamily' => "0",
315
+ }
316
+ HTTParty::Parsers::XML.parse(topic_xml)["rsp"]["photos"]["photo"].each do |k,v|
317
+ v.should == expected_topic_hash[k]
318
+ end
319
+ end
320
+
321
+ it "should handle an emtpy array (ActiveSupport Compatible)" do
322
+ blog_xml = <<-XML
323
+ <blog>
324
+ <posts type="array"></posts>
325
+ </blog>
326
+ XML
327
+ expected_blog_hash = {"blog" => {"posts" => []}}
328
+ HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
329
+ end
330
+
331
+ it "should handle empty array with whitespace from xml (ActiveSupport Compatible)" do
332
+ blog_xml = <<-XML
333
+ <blog>
334
+ <posts type="array">
335
+ </posts>
336
+ </blog>
337
+ XML
338
+ expected_blog_hash = {"blog" => {"posts" => []}}
339
+ HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
340
+ end
341
+
342
+ it "should handle array with one entry from_xml (ActiveSupport Compatible)" do
343
+ blog_xml = <<-XML
344
+ <blog>
345
+ <posts type="array">
346
+ <post>a post</post>
347
+ </posts>
348
+ </blog>
349
+ XML
350
+ expected_blog_hash = {"blog" => {"posts" => ["a post"]}}
351
+ HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
352
+ end
353
+
354
+ it "should handle array with multiple entries from xml (ActiveSupport Compatible)" do
355
+ blog_xml = <<-XML
356
+ <blog>
357
+ <posts type="array">
358
+ <post>a post</post>
359
+ <post>another post</post>
360
+ </posts>
361
+ </blog>
362
+ XML
363
+ expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}}
364
+ HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
365
+ end
366
+
367
+ it "should handle file types (ActiveSupport Compatible)" do
368
+ blog_xml = <<-XML
369
+ <blog>
370
+ <logo type="file" name="logo.png" content_type="image/png">
371
+ </logo>
372
+ </blog>
373
+ XML
374
+ hash = HTTParty::Parsers::XML.parse(blog_xml)
375
+ hash.should have_key('blog')
376
+ hash['blog'].should have_key('logo')
377
+
378
+ file = hash['blog']['logo']
379
+ file.original_filename.should == 'logo.png'
380
+ file.content_type.should == 'image/png'
381
+ end
382
+
383
+ it "should handle file from xml with defaults (ActiveSupport Compatible)" do
384
+ blog_xml = <<-XML
385
+ <blog>
386
+ <logo type="file">
387
+ </logo>
388
+ </blog>
389
+ XML
390
+ file = HTTParty::Parsers::XML.parse(blog_xml)['blog']['logo']
391
+ file.original_filename.should == 'untitled'
392
+ file.content_type.should == 'application/octet-stream'
393
+ end
394
+
395
+ it "should handle xsd like types from xml (ActiveSupport Compatible)" do
396
+ bacon_xml = <<-EOT
397
+ <bacon>
398
+ <weight type="double">0.5</weight>
399
+ <price type="decimal">12.50</price>
400
+ <chunky type="boolean"> 1 </chunky>
401
+ <expires-at type="dateTime">2007-12-25T12:34:56+0000</expires-at>
402
+ <notes type="string"></notes>
403
+ <illustration type="base64Binary">YmFiZS5wbmc=</illustration>
404
+ </bacon>
405
+ EOT
406
+
407
+ expected_bacon_hash = {
408
+ 'weight' => 0.5,
409
+ 'chunky' => true,
410
+ 'price' => BigDecimal("12.50"),
411
+ 'expires_at' => Time.utc(2007,12,25,12,34,56),
412
+ 'notes' => "",
413
+ 'illustration' => "babe.png"
414
+ }
415
+
416
+ HTTParty::Parsers::XML.parse(bacon_xml)["bacon"].should == expected_bacon_hash
417
+ end
418
+
419
+ it "should let type trickle through when unknown (ActiveSupport Compatible)" do
420
+ product_xml = <<-EOT
421
+ <product>
422
+ <weight type="double">0.5</weight>
423
+ <image type="ProductImage"><filename>image.gif</filename></image>
424
+
425
+ </product>
426
+ EOT
427
+
428
+ expected_product_hash = {
429
+ 'weight' => 0.5,
430
+ 'image' => {'type' => 'ProductImage', 'filename' => 'image.gif' },
431
+ }
432
+
433
+ HTTParty::Parsers::XML.parse(product_xml)["product"].should == expected_product_hash
434
+ end
435
+
436
+ it "should handle unescaping from xml (ActiveResource Compatible)" do
437
+ xml_string = '<person><bare-string>First &amp; Last Name</bare-string><pre-escaped-string>First &amp;amp; Last Name</pre-escaped-string></person>'
438
+ expected_hash = {
439
+ 'bare_string' => 'First & Last Name',
440
+ 'pre_escaped_string' => 'First &amp; Last Name'
441
+ }
442
+
443
+ HTTParty::Parsers::XML.parse(xml_string)['person'].should == expected_hash
444
+ end
445
+ end
@@ -0,0 +1,205 @@
1
+ require 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 basic auth when configured" do
40
+ @request.options[:basic_auth] = {:username => 'foobar', :password => 'secret'}
41
+ @request.send(:setup_raw_request)
42
+ @request.instance_variable_get(:@raw_request)['authorization'].should_not be_nil
43
+ end
44
+ end
45
+
46
+ describe '#format_from_mimetype' do
47
+ it 'should handle text/xml' do
48
+ ["text/xml", "text/xml; charset=iso8859-1"].each do |ct|
49
+ @request.send(:format_from_mimetype, ct).should == :xml
50
+ end
51
+ end
52
+
53
+ it 'should handle application/xml' do
54
+ ["application/xml", "application/xml; charset=iso8859-1"].each do |ct|
55
+ @request.send(:format_from_mimetype, ct).should == :xml
56
+ end
57
+ end
58
+
59
+ it 'should handle text/json' do
60
+ ["text/json", "text/json; charset=iso8859-1"].each do |ct|
61
+ @request.send(:format_from_mimetype, ct).should == :json
62
+ end
63
+ end
64
+
65
+ it 'should handle application/json' do
66
+ ["application/json", "application/json; charset=iso8859-1"].each do |ct|
67
+ @request.send(:format_from_mimetype, ct).should == :json
68
+ end
69
+ end
70
+
71
+ it 'should handle text/javascript' do
72
+ ["text/javascript", "text/javascript; charset=iso8859-1"].each do |ct|
73
+ @request.send(:format_from_mimetype, ct).should == :json
74
+ end
75
+ end
76
+
77
+ it 'should handle application/javascript' do
78
+ ["application/javascript", "application/javascript; charset=iso8859-1"].each do |ct|
79
+ @request.send(:format_from_mimetype, ct).should == :json
80
+ end
81
+ end
82
+ end
83
+
84
+ describe 'parsing responses' do
85
+ it 'should handle xml automatically' do
86
+ xml = %q[<books><book><id>1234</id><name>Foo Bar!</name></book></books>]
87
+ @request.options[:format] = :xml
88
+ @request.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
89
+ end
90
+
91
+ it 'should handle json automatically' do
92
+ json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}]
93
+ @request.options[:format] = :json
94
+ @request.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
95
+ end
96
+
97
+ it 'should handle yaml automatically' do
98
+ yaml = "books: \n book: \n name: Foo Bar!\n id: \"1234\"\n"
99
+ @request.options[:format] = :yaml
100
+ @request.send(:parse_response, yaml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
101
+ end
102
+
103
+ it "should include any HTTP headers in the returned response" do
104
+ @request.options[:format] = :html
105
+ response = stub_response "Content"
106
+ response.initialize_http_header("key" => "value")
107
+
108
+ @request.perform.headers.should == { "key" => ["value"] }
109
+ end
110
+
111
+ describe 'with non-200 responses' do
112
+
113
+ it 'should return a valid object for 4xx response' do
114
+ stub_response '<foo><bar>yes</bar></foo>', 401
115
+ resp = @request.perform
116
+ resp.code.should == 401
117
+ resp.body.should == "<foo><bar>yes</bar></foo>"
118
+ resp['foo']['bar'].should == "yes"
119
+ end
120
+
121
+ it 'should return a valid object for 5xx response' do
122
+ stub_response '<foo><bar>error</bar></foo>', 500
123
+ resp = @request.perform
124
+ resp.code.should == 500
125
+ resp.body.should == "<foo><bar>error</bar></foo>"
126
+ resp['foo']['bar'].should == "error"
127
+ end
128
+
129
+ end
130
+ end
131
+
132
+ describe "with empty responses" do
133
+ after do
134
+ @request.options[:format] = :xml
135
+ @request.perform.should be_nil
136
+ end
137
+ it "should not attempt to parse empty responses" do
138
+ stub_response "", 204
139
+ end
140
+ it "should not attempt to parse nil responses" do
141
+ stub_response nil, 204
142
+ end
143
+ it "should not attempt to parse blank responses" do
144
+ stub_response " ", 201
145
+ end
146
+ end
147
+
148
+ it "should not fail for missing mime type" do
149
+ stub_response "Content for you"
150
+ @request.options[:format] = :html
151
+ @request.perform.should == 'Content for you'
152
+ end
153
+
154
+ describe "a request that redirects" do
155
+ before(:each) do
156
+ @redirect = stub_response("", 302)
157
+ @redirect['location'] = '/foo'
158
+
159
+ @ok = stub_response('<hash><foo>bar</foo></hash>', 200)
160
+ end
161
+
162
+ describe "once" do
163
+ before(:each) do
164
+ @http.stub!(:request).and_return(@redirect, @ok)
165
+ end
166
+
167
+ it "should be handled by GET transparently" do
168
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
169
+ end
170
+
171
+ it "should be handled by POST transparently" do
172
+ @request.http_method = Net::HTTP::Post
173
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
174
+ end
175
+
176
+ it "should be handled by DELETE transparently" do
177
+ @request.http_method = Net::HTTP::Delete
178
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
179
+ end
180
+
181
+ it "should be handled by PUT transparently" do
182
+ @request.http_method = Net::HTTP::Put
183
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
184
+ end
185
+ end
186
+
187
+ describe "infinitely" do
188
+ before(:each) do
189
+ @http.stub!(:request).and_return(@redirect)
190
+ end
191
+
192
+ it "should raise an exception" do
193
+ lambda { @request.perform }.should raise_error(HTTParty::RedirectionTooDeep)
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ describe HTTParty::Request, "with POST http method" do
200
+ it "should raise argument error if query is not a hash" do
201
+ lambda {
202
+ HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :format => :xml, :query => 'astring').perform
203
+ }.should raise_error(ArgumentError)
204
+ end
205
+ end