rest-client 1.6.14 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +6 -6
  3. data/.rspec +2 -1
  4. data/.rubocop-disables.yml +384 -0
  5. data/.rubocop.yml +3 -0
  6. data/.travis.yml +46 -1
  7. data/AUTHORS +28 -5
  8. data/Gemfile +5 -1
  9. data/LICENSE +21 -0
  10. data/README.md +784 -0
  11. data/Rakefile +95 -12
  12. data/bin/restclient +11 -12
  13. data/history.md +180 -16
  14. data/lib/restclient.rb +25 -11
  15. data/lib/restclient/abstract_response.rb +171 -51
  16. data/lib/restclient/exceptions.rb +102 -56
  17. data/lib/restclient/params_array.rb +72 -0
  18. data/lib/restclient/payload.rb +43 -74
  19. data/lib/restclient/platform.rb +22 -2
  20. data/lib/restclient/raw_response.rb +7 -3
  21. data/lib/restclient/request.rb +672 -179
  22. data/lib/restclient/resource.rb +6 -7
  23. data/lib/restclient/response.rb +64 -10
  24. data/lib/restclient/utils.rb +235 -0
  25. data/lib/restclient/version.rb +2 -1
  26. data/lib/restclient/windows.rb +8 -0
  27. data/lib/restclient/windows/root_certs.rb +105 -0
  28. data/rest-client.gemspec +16 -11
  29. data/rest-client.windows.gemspec +19 -0
  30. data/spec/helpers.rb +22 -0
  31. data/spec/integration/_lib.rb +1 -0
  32. data/spec/integration/capath_verisign/415660c1.0 +14 -0
  33. data/spec/integration/capath_verisign/7651b327.0 +14 -0
  34. data/spec/integration/capath_verisign/README +8 -0
  35. data/spec/integration/capath_verisign/verisign.crt +14 -0
  36. data/spec/integration/httpbin_spec.rb +87 -0
  37. data/spec/integration/integration_spec.rb +125 -0
  38. data/spec/integration/request_spec.rb +72 -20
  39. data/spec/spec_helper.rb +29 -0
  40. data/spec/unit/_lib.rb +1 -0
  41. data/spec/unit/abstract_response_spec.rb +145 -0
  42. data/spec/unit/exceptions_spec.rb +108 -0
  43. data/spec/{master_shake.jpg → unit/master_shake.jpg} +0 -0
  44. data/spec/unit/params_array_spec.rb +36 -0
  45. data/spec/{payload_spec.rb → unit/payload_spec.rb} +73 -54
  46. data/spec/{raw_response_spec.rb → unit/raw_response_spec.rb} +5 -4
  47. data/spec/unit/request2_spec.rb +54 -0
  48. data/spec/unit/request_spec.rb +1250 -0
  49. data/spec/unit/resource_spec.rb +134 -0
  50. data/spec/unit/response_spec.rb +241 -0
  51. data/spec/unit/restclient_spec.rb +79 -0
  52. data/spec/unit/utils_spec.rb +147 -0
  53. data/spec/unit/windows/root_certs_spec.rb +22 -0
  54. metadata +143 -53
  55. data/README.rdoc +0 -300
  56. data/lib/restclient/net_http_ext.rb +0 -55
  57. data/spec/abstract_response_spec.rb +0 -85
  58. data/spec/base.rb +0 -13
  59. data/spec/exceptions_spec.rb +0 -98
  60. data/spec/integration_spec.rb +0 -38
  61. data/spec/request2_spec.rb +0 -35
  62. data/spec/request_spec.rb +0 -528
  63. data/spec/resource_spec.rb +0 -136
  64. data/spec/response_spec.rb +0 -169
  65. data/spec/restclient_spec.rb +0 -73
@@ -0,0 +1,29 @@
1
+ require 'webmock/rspec'
2
+ require 'rest-client'
3
+
4
+ require_relative './helpers'
5
+
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.raise_errors_for_deprecations!
9
+
10
+ # Run specs in random order to surface order dependencies. If you find an
11
+ # order dependency and want to debug it, you can fix the order by providing
12
+ # the seed, which is printed after each run.
13
+ # --seed 1234
14
+ config.order = 'random'
15
+
16
+ # always run with ruby warnings enabled
17
+ # TODO: figure out why this is so obscenely noisy (rspec bug?)
18
+ # config.warnings = true
19
+
20
+ # add helpers
21
+ config.include Helpers, :include_helpers
22
+
23
+ config.mock_with :rspec do |mocks|
24
+ mocks.yield_receiver_to_any_instance_implementation_blocks = true
25
+ end
26
+ end
27
+
28
+ # always run with ruby warnings enabled (see above)
29
+ $VERBOSE = true
@@ -0,0 +1 @@
1
+ require_relative '../spec_helper'
@@ -0,0 +1,145 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestClient::AbstractResponse, :include_helpers do
4
+
5
+ class MyAbstractResponse
6
+
7
+ include RestClient::AbstractResponse
8
+
9
+ attr_accessor :size
10
+
11
+ def initialize net_http_res, request
12
+ @net_http_res = net_http_res
13
+ @request = request
14
+ end
15
+
16
+ end
17
+
18
+ before do
19
+ @net_http_res = double('net http response')
20
+ @request = request_double(url: 'http://example.com', method: 'get')
21
+ @response = MyAbstractResponse.new(@net_http_res, @request)
22
+ end
23
+
24
+ it "fetches the numeric response code" do
25
+ expect(@net_http_res).to receive(:code).and_return('200')
26
+ expect(@response.code).to eq 200
27
+ end
28
+
29
+ it "has a nice description" do
30
+ expect(@net_http_res).to receive(:to_hash).and_return({'Content-Type' => ['application/pdf']})
31
+ expect(@net_http_res).to receive(:code).and_return('200')
32
+ expect(@response.description).to eq "200 OK | application/pdf bytes\n"
33
+ end
34
+
35
+ describe '.beautify_headers' do
36
+ it "beautifies the headers by turning the keys to symbols" do
37
+ h = RestClient::AbstractResponse.beautify_headers('content-type' => [ 'x' ])
38
+ expect(h.keys.first).to eq :content_type
39
+ end
40
+
41
+ it "beautifies the headers by turning the values to strings instead of one-element arrays" do
42
+ h = RestClient::AbstractResponse.beautify_headers('x' => [ 'text/html' ] )
43
+ expect(h.values.first).to eq 'text/html'
44
+ end
45
+
46
+ it 'joins multiple header values by comma' do
47
+ expect(RestClient::AbstractResponse.beautify_headers(
48
+ {'My-Header' => ['one', 'two']}
49
+ )).to eq({:my_header => 'one, two'})
50
+ end
51
+
52
+ it 'leaves set-cookie headers as array' do
53
+ expect(RestClient::AbstractResponse.beautify_headers(
54
+ {'Set-Cookie' => ['cookie1=foo', 'cookie2=bar']}
55
+ )).to eq({:set_cookie => ['cookie1=foo', 'cookie2=bar']})
56
+ end
57
+ end
58
+
59
+ it "fetches the headers" do
60
+ expect(@net_http_res).to receive(:to_hash).and_return('content-type' => [ 'text/html' ])
61
+ expect(@response.headers).to eq({ :content_type => 'text/html' })
62
+ end
63
+
64
+ it "extracts cookies from response headers" do
65
+ expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
66
+ expect(@response.cookies).to eq({ 'session_id' => '1' })
67
+ end
68
+
69
+ it "extract strange cookies" do
70
+ expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/'])
71
+ expect(@response.headers).to eq({:set_cookie => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/']})
72
+ expect(@response.cookies).to eq({ 'session_id' => 'ZJ/HQVH6YE+rVkTpn0zvTQ==' })
73
+ end
74
+
75
+ it "doesn't escape cookies" do
76
+ expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca; path=/'])
77
+ expect(@response.cookies).to eq({ 'session_id' => 'BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca' })
78
+ end
79
+
80
+ describe '.cookie_jar' do
81
+ it 'extracts cookies into cookie jar' do
82
+ expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
83
+ expect(@response.cookie_jar).to be_a HTTP::CookieJar
84
+
85
+ cookie = @response.cookie_jar.cookies.first
86
+ expect(cookie.domain).to eq 'example.com'
87
+ expect(cookie.name).to eq 'session_id'
88
+ expect(cookie.value).to eq '1'
89
+ expect(cookie.path).to eq '/'
90
+ end
91
+
92
+ it 'handles cookies when URI scheme is implicit' do
93
+ net_http_res = double('net http response')
94
+ expect(net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
95
+ request = double(url: 'example.com', uri: URI.parse('http://example.com'),
96
+ method: 'get', cookie_jar: HTTP::CookieJar.new)
97
+ response = MyAbstractResponse.new(net_http_res, request)
98
+ expect(response.cookie_jar).to be_a HTTP::CookieJar
99
+
100
+ cookie = response.cookie_jar.cookies.first
101
+ expect(cookie.domain).to eq 'example.com'
102
+ expect(cookie.name).to eq 'session_id'
103
+ expect(cookie.value).to eq '1'
104
+ expect(cookie.path).to eq '/'
105
+ end
106
+ end
107
+
108
+ it "can access the net http result directly" do
109
+ expect(@response.net_http_res).to eq @net_http_res
110
+ end
111
+
112
+ describe "#return!" do
113
+ it "should return the response itself on 200-codes" do
114
+ expect(@net_http_res).to receive(:code).and_return('200')
115
+ expect(@response.return!).to be_equal(@response)
116
+ end
117
+
118
+ it "should raise RequestFailed on unknown codes" do
119
+ expect(@net_http_res).to receive(:code).and_return('1000')
120
+ expect { @response.return! }.to raise_error RestClient::RequestFailed
121
+ end
122
+
123
+ it "should raise an error on a redirection after non-GET/HEAD requests" do
124
+ expect(@net_http_res).to receive(:code).and_return('301')
125
+ expect(@request).to receive(:method).and_return('put')
126
+ expect(@response).not_to receive(:follow_redirection)
127
+ expect { @response.return! }.to raise_error RestClient::RequestFailed
128
+ end
129
+
130
+ it "should follow 302 redirect" do
131
+ expect(@net_http_res).to receive(:code).and_return('302')
132
+ expect(@response).to receive(:check_max_redirects).and_return('fake-check')
133
+ expect(@response).to receive(:follow_redirection).and_return('fake-redirection')
134
+ expect(@response.return!).to eq 'fake-redirection'
135
+ end
136
+
137
+ it "should gracefully handle 302 redirect with no location header" do
138
+ @net_http_res = response_double(code: 302, location: nil)
139
+ @request = request_double()
140
+ @response = MyAbstractResponse.new(@net_http_res, @request)
141
+ expect(@response).to receive(:check_max_redirects).and_return('fake-check')
142
+ expect { @response.return! }.to raise_error RestClient::Found
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,108 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestClient::Exception do
4
+ it "returns a 'message' equal to the class name if the message is not set, because 'message' should not be nil" do
5
+ e = RestClient::Exception.new
6
+ expect(e.message).to eq "RestClient::Exception"
7
+ end
8
+
9
+ it "returns the 'message' that was set" do
10
+ e = RestClient::Exception.new
11
+ message = "An explicitly set message"
12
+ e.message = message
13
+ expect(e.message).to eq message
14
+ end
15
+
16
+ it "sets the exception message to ErrorMessage" do
17
+ expect(RestClient::ResourceNotFound.new.message).to eq 'Not Found'
18
+ end
19
+
20
+ it "contains exceptions in RestClient" do
21
+ expect(RestClient::Unauthorized.new).to be_a_kind_of(RestClient::Exception)
22
+ expect(RestClient::ServerBrokeConnection.new).to be_a_kind_of(RestClient::Exception)
23
+ end
24
+ end
25
+
26
+ describe RestClient::ServerBrokeConnection do
27
+ it "should have a default message of 'Server broke connection'" do
28
+ e = RestClient::ServerBrokeConnection.new
29
+ expect(e.message).to eq 'Server broke connection'
30
+ end
31
+ end
32
+
33
+ describe RestClient::RequestFailed do
34
+ before do
35
+ @response = double('HTTP Response', :code => '502')
36
+ end
37
+
38
+ it "stores the http response on the exception" do
39
+ response = "response"
40
+ begin
41
+ raise RestClient::RequestFailed, response
42
+ rescue RestClient::RequestFailed => e
43
+ expect(e.response).to eq response
44
+ end
45
+ end
46
+
47
+ it "http_code convenience method for fetching the code as an integer" do
48
+ expect(RestClient::RequestFailed.new(@response).http_code).to eq 502
49
+ end
50
+
51
+ it "http_body convenience method for fetching the body (decoding when necessary)" do
52
+ expect(RestClient::RequestFailed.new(@response).http_code).to eq 502
53
+ expect(RestClient::RequestFailed.new(@response).message).to eq 'HTTP status code 502'
54
+ end
55
+
56
+ it "shows the status code in the message" do
57
+ expect(RestClient::RequestFailed.new(@response).to_s).to match(/502/)
58
+ end
59
+ end
60
+
61
+ describe RestClient::ResourceNotFound do
62
+ it "also has the http response attached" do
63
+ response = "response"
64
+ begin
65
+ raise RestClient::ResourceNotFound, response
66
+ rescue RestClient::ResourceNotFound => e
67
+ expect(e.response).to eq response
68
+ end
69
+ end
70
+
71
+ it 'stores the body on the response of the exception' do
72
+ body = "body"
73
+ stub_request(:get, "www.example.com").to_return(:body => body, :status => 404)
74
+ begin
75
+ RestClient.get "www.example.com"
76
+ raise
77
+ rescue RestClient::ResourceNotFound => e
78
+ expect(e.response.body).to eq body
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "backwards compatibility" do
84
+ it 'aliases RestClient::NotFound as ResourceNotFound' do
85
+ expect(RestClient::ResourceNotFound).to eq RestClient::NotFound
86
+ end
87
+
88
+ it 'aliases old names for HTTP 413, 414, 416' do
89
+ expect(RestClient::RequestEntityTooLarge).to eq RestClient::PayloadTooLarge
90
+ expect(RestClient::RequestURITooLong).to eq RestClient::URITooLong
91
+ expect(RestClient::RequestedRangeNotSatisfiable).to eq RestClient::RangeNotSatisfiable
92
+ end
93
+
94
+ it 'subclasses NotFound from RequestFailed, ExceptionWithResponse' do
95
+ expect(RestClient::NotFound).to be < RestClient::RequestFailed
96
+ expect(RestClient::NotFound).to be < RestClient::ExceptionWithResponse
97
+ end
98
+
99
+ it 'subclasses timeout from RestClient::RequestTimeout, RequestFailed, EWR' do
100
+ expect(RestClient::Exceptions::OpenTimeout).to be < RestClient::Exceptions::Timeout
101
+ expect(RestClient::Exceptions::ReadTimeout).to be < RestClient::Exceptions::Timeout
102
+
103
+ expect(RestClient::Exceptions::Timeout).to be < RestClient::RequestTimeout
104
+ expect(RestClient::Exceptions::Timeout).to be < RestClient::RequestFailed
105
+ expect(RestClient::Exceptions::Timeout).to be < RestClient::ExceptionWithResponse
106
+ end
107
+
108
+ end
@@ -0,0 +1,36 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestClient::ParamsArray do
4
+
5
+ describe '.new' do
6
+ it 'accepts various types of containers' do
7
+ as_array = [[:foo, 123], [:foo, 456], [:bar, 789], [:empty, nil]]
8
+ [
9
+ [[:foo, 123], [:foo, 456], [:bar, 789], [:empty, nil]],
10
+ [{foo: 123}, {foo: 456}, {bar: 789}, {empty: nil}],
11
+ [{foo: 123}, {foo: 456}, {bar: 789}, {empty: nil}],
12
+ [{foo: 123}, [:foo, 456], {bar: 789}, {empty: nil}],
13
+ [{foo: 123}, [:foo, 456], {bar: 789}, [:empty]],
14
+ ].each do |input|
15
+ expect(RestClient::ParamsArray.new(input).to_a).to eq as_array
16
+ end
17
+
18
+ expect(RestClient::ParamsArray.new([]).to_a).to eq []
19
+ expect(RestClient::ParamsArray.new([]).empty?).to eq true
20
+ end
21
+
22
+ it 'rejects various invalid input' do
23
+ expect {
24
+ RestClient::ParamsArray.new([[]])
25
+ }.to raise_error(IndexError)
26
+
27
+ expect {
28
+ RestClient::ParamsArray.new([[1,2,3]])
29
+ }.to raise_error(ArgumentError)
30
+
31
+ expect {
32
+ RestClient::ParamsArray.new([1,2,3])
33
+ }.to raise_error(NoMethodError)
34
+ end
35
+ end
36
+ end
@@ -1,59 +1,68 @@
1
1
  # encoding: binary
2
- require File.join(File.dirname(File.expand_path(__FILE__)), 'base')
2
+
3
+ require_relative '_lib'
3
4
 
4
5
  describe RestClient::Payload do
6
+ context "Base Payload" do
7
+ it "should reset stream after to_s" do
8
+ payload = RestClient::Payload::Base.new('foobar')
9
+ expect(payload.to_s).to eq 'foobar'
10
+ expect(payload.to_s).to eq 'foobar'
11
+ end
12
+ end
13
+
5
14
  context "A regular Payload" do
6
15
  it "should use standard enctype as default content-type" do
7
- RestClient::Payload::UrlEncoded.new({}).headers['Content-Type'].
8
- should eq 'application/x-www-form-urlencoded'
16
+ expect(RestClient::Payload::UrlEncoded.new({}).headers['Content-Type']).
17
+ to eq 'application/x-www-form-urlencoded'
9
18
  end
10
19
 
11
20
  it "should form properly encoded params" do
12
- RestClient::Payload::UrlEncoded.new({:foo => 'bar'}).to_s.
13
- should eq "foo=bar"
14
- ["foo=bar&baz=qux", "baz=qux&foo=bar"].should include(
21
+ expect(RestClient::Payload::UrlEncoded.new({:foo => 'bar'}).to_s).
22
+ to eq "foo=bar"
23
+ expect(["foo=bar&baz=qux", "baz=qux&foo=bar"]).to include(
15
24
  RestClient::Payload::UrlEncoded.new({:foo => 'bar', :baz => 'qux'}).to_s)
16
25
  end
17
26
 
18
27
  it "should escape parameters" do
19
- RestClient::Payload::UrlEncoded.new({'foo ' => 'bar'}).to_s.
20
- should eq "foo%20=bar"
28
+ expect(RestClient::Payload::UrlEncoded.new({'foo + bar' => 'baz'}).to_s).
29
+ to eq "foo+%2B+bar=baz"
21
30
  end
22
31
 
23
32
  it "should properly handle hashes as parameter" do
24
- RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz'}}).to_s.
25
- should eq "foo[bar]=baz"
26
- RestClient::Payload::UrlEncoded.new({:foo => {:bar => {:baz => 'qux'}}}).to_s.
27
- should eq "foo[bar][baz]=qux"
33
+ expect(RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz'}}).to_s).
34
+ to eq "foo[bar]=baz"
35
+ expect(RestClient::Payload::UrlEncoded.new({:foo => {:bar => {:baz => 'qux'}}}).to_s).
36
+ to eq "foo[bar][baz]=qux"
28
37
  end
29
38
 
30
39
  it "should handle many attributes inside a hash" do
31
40
  parameters = RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz', :baz => 'qux'}}).to_s
32
- parameters.should include("foo[bar]=baz", "foo[baz]=qux")
41
+ expect(parameters).to eq 'foo[bar]=baz&foo[baz]=qux'
33
42
  end
34
43
 
35
- it "should handle attributes inside a an array inside an hash" do
44
+ it "should handle attributes inside an array inside an hash" do
36
45
  parameters = RestClient::Payload::UrlEncoded.new({"foo" => [{"bar" => 'baz'}, {"bar" => 'qux'}]}).to_s
37
- parameters.should include("foo[bar]=baz", "foo[bar]=qux")
46
+ expect(parameters).to eq 'foo[][bar]=baz&foo[][bar]=qux'
38
47
  end
39
48
 
40
- it "should handle attributes inside a an array inside an array inside an hash" do
41
- parameters = RestClient::Payload::UrlEncoded.new({"foo" => [[{"bar" => 'baz'}, {"bar" => 'qux'}]]}).to_s
42
- parameters.should include("foo[bar]=baz", "foo[bar]=qux")
49
+ it "should handle arrays inside a hash inside a hash" do
50
+ parameters = RestClient::Payload::UrlEncoded.new({"foo" => {'even' => [0, 2], 'odd' => [1, 3]}}).to_s
51
+ expect(parameters).to eq 'foo[even][]=0&foo[even][]=2&foo[odd][]=1&foo[odd][]=3'
43
52
  end
44
53
 
45
54
  it "should form properly use symbols as parameters" do
46
- RestClient::Payload::UrlEncoded.new({:foo => :bar}).to_s.
47
- should eq "foo=bar"
48
- RestClient::Payload::UrlEncoded.new({:foo => {:bar => :baz}}).to_s.
49
- should eq "foo[bar]=baz"
55
+ expect(RestClient::Payload::UrlEncoded.new({:foo => :bar}).to_s).
56
+ to eq "foo=bar"
57
+ expect(RestClient::Payload::UrlEncoded.new({:foo => {:bar => :baz}}).to_s).
58
+ to eq "foo[bar]=baz"
50
59
  end
51
60
 
52
61
  it "should properly handle arrays as repeated parameters" do
53
- RestClient::Payload::UrlEncoded.new({:foo => ['bar']}).to_s.
54
- should eq "foo[]=bar"
55
- RestClient::Payload::UrlEncoded.new({:foo => ['bar', 'baz']}).to_s.
56
- should eq "foo[]=bar&foo[]=baz"
62
+ expect(RestClient::Payload::UrlEncoded.new({:foo => ['bar']}).to_s).
63
+ to eq "foo[]=bar"
64
+ expect(RestClient::Payload::UrlEncoded.new({:foo => ['bar', 'baz']}).to_s).
65
+ to eq "foo[]=bar&foo[]=baz"
57
66
  end
58
67
 
59
68
  it 'should not close if stream already closed' do
@@ -66,8 +75,8 @@ describe RestClient::Payload do
66
75
  context "A multipart Payload" do
67
76
  it "should use standard enctype as default content-type" do
68
77
  m = RestClient::Payload::Multipart.new({})
69
- m.stub(:boundary).and_return(123)
70
- m.headers['Content-Type'].should eq 'multipart/form-data; boundary=123'
78
+ allow(m).to receive(:boundary).and_return(123)
79
+ expect(m.headers['Content-Type']).to eq 'multipart/form-data; boundary=123'
71
80
  end
72
81
 
73
82
  it 'should not error on close if stream already closed' do
@@ -77,7 +86,7 @@ describe RestClient::Payload do
77
86
 
78
87
  it "should form properly separated multipart data" do
79
88
  m = RestClient::Payload::Multipart.new([[:bar, "baz"], [:foo, "bar"]])
80
- m.to_s.should eq <<-EOS
89
+ expect(m.to_s).to eq <<-EOS
81
90
  --#{m.boundary}\r
82
91
  Content-Disposition: form-data; name="bar"\r
83
92
  \r
@@ -92,7 +101,7 @@ bar\r
92
101
 
93
102
  it "should not escape parameters names" do
94
103
  m = RestClient::Payload::Multipart.new([["bar ", "baz"]])
95
- m.to_s.should eq <<-EOS
104
+ expect(m.to_s).to eq <<-EOS
96
105
  --#{m.boundary}\r
97
106
  Content-Disposition: form-data; name="bar "\r
98
107
  \r
@@ -104,7 +113,7 @@ baz\r
104
113
  it "should form properly separated multipart data" do
105
114
  f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
106
115
  m = RestClient::Payload::Multipart.new({:foo => f})
107
- m.to_s.should eq <<-EOS
116
+ expect(m.to_s).to eq <<-EOS
108
117
  --#{m.boundary}\r
109
118
  Content-Disposition: form-data; name="foo"; filename="master_shake.jpg"\r
110
119
  Content-Type: image/jpeg\r
@@ -117,7 +126,7 @@ Content-Type: image/jpeg\r
117
126
  it "should ignore the name attribute when it's not set" do
118
127
  f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
119
128
  m = RestClient::Payload::Multipart.new({nil => f})
120
- m.to_s.should eq <<-EOS
129
+ expect(m.to_s).to eq <<-EOS
121
130
  --#{m.boundary}\r
122
131
  Content-Disposition: form-data; filename="master_shake.jpg"\r
123
132
  Content-Type: image/jpeg\r
@@ -132,7 +141,7 @@ Content-Type: image/jpeg\r
132
141
  f.instance_eval "def content_type; 'text/plain'; end"
133
142
  f.instance_eval "def original_filename; 'foo.txt'; end"
134
143
  m = RestClient::Payload::Multipart.new({:foo => f})
135
- m.to_s.should eq <<-EOS
144
+ expect(m.to_s).to eq <<-EOS
136
145
  --#{m.boundary}\r
137
146
  Content-Disposition: form-data; name="foo"; filename="foo.txt"\r
138
147
  Content-Type: text/plain\r
@@ -144,7 +153,7 @@ Content-Type: text/plain\r
144
153
 
145
154
  it "should handle hash in hash parameters" do
146
155
  m = RestClient::Payload::Multipart.new({:bar => {:baz => "foo"}})
147
- m.to_s.should eq <<-EOS
156
+ expect(m.to_s).to eq <<-EOS
148
157
  --#{m.boundary}\r
149
158
  Content-Disposition: form-data; name="bar[baz]"\r
150
159
  \r
@@ -156,7 +165,7 @@ foo\r
156
165
  f.instance_eval "def content_type; 'text/plain'; end"
157
166
  f.instance_eval "def original_filename; 'foo.txt'; end"
158
167
  m = RestClient::Payload::Multipart.new({:foo => {:bar => f}})
159
- m.to_s.should eq <<-EOS
168
+ expect(m.to_s).to eq <<-EOS
160
169
  --#{m.boundary}\r
161
170
  Content-Disposition: form-data; name="foo[bar]"; filename="foo.txt"\r
162
171
  Content-Type: text/plain\r
@@ -166,29 +175,36 @@ Content-Type: text/plain\r
166
175
  EOS
167
176
  end
168
177
 
178
+ it 'should correctly format hex boundary' do
179
+ allow(SecureRandom).to receive(:base64).with(12).and_return('TGs89+ttw/xna6TV')
180
+ f = File.new(File.dirname(__FILE__) + '/master_shake.jpg')
181
+ m = RestClient::Payload::Multipart.new({:foo => f})
182
+ expect(m.boundary).to eq('-' * 4 + 'RubyFormBoundary' + 'TGs89AttwBxna6TV')
183
+ end
184
+
169
185
  end
170
186
 
171
187
  context "streamed payloads" do
172
188
  it "should properly determine the size of file payloads" do
173
189
  f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
174
190
  payload = RestClient::Payload.generate(f)
175
- payload.size.should eq 76_988
176
- payload.length.should eq 76_988
191
+ expect(payload.size).to eq 76_988
192
+ expect(payload.length).to eq 76_988
177
193
  end
178
194
 
179
195
  it "should properly determine the size of other kinds of streaming payloads" do
180
196
  s = StringIO.new 'foo'
181
197
  payload = RestClient::Payload.generate(s)
182
- payload.size.should eq 3
183
- payload.length.should eq 3
198
+ expect(payload.size).to eq 3
199
+ expect(payload.length).to eq 3
184
200
 
185
201
  begin
186
202
  f = Tempfile.new "rest-client"
187
203
  f.write 'foo bar'
188
204
 
189
205
  payload = RestClient::Payload.generate(f)
190
- payload.size.should eq 7
191
- payload.length.should eq 7
206
+ expect(payload.size).to eq 7
207
+ expect(payload.length).to eq 7
192
208
  ensure
193
209
  f.close
194
210
  end
@@ -197,48 +213,51 @@ Content-Type: text/plain\r
197
213
 
198
214
  context "Payload generation" do
199
215
  it "should recognize standard urlencoded params" do
200
- RestClient::Payload.generate({"foo" => 'bar'}).should be_kind_of(RestClient::Payload::UrlEncoded)
216
+ expect(RestClient::Payload.generate({"foo" => 'bar'})).to be_kind_of(RestClient::Payload::UrlEncoded)
201
217
  end
202
218
 
203
219
  it "should recognize multipart params" do
204
220
  f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
205
- RestClient::Payload.generate({"foo" => f}).should be_kind_of(RestClient::Payload::Multipart)
221
+ expect(RestClient::Payload.generate({"foo" => f})).to be_kind_of(RestClient::Payload::Multipart)
206
222
  end
207
223
 
208
224
  it "should be multipart if forced" do
209
- RestClient::Payload.generate({"foo" => "bar", :multipart => true}).should be_kind_of(RestClient::Payload::Multipart)
225
+ expect(RestClient::Payload.generate({"foo" => "bar", :multipart => true})).to be_kind_of(RestClient::Payload::Multipart)
210
226
  end
211
227
 
228
+ it "should handle deeply nested multipart" do
229
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
230
+ params = {foo: RestClient::ParamsArray.new({nested: f})}
231
+ expect(RestClient::Payload.generate(params)).to be_kind_of(RestClient::Payload::Multipart)
232
+ end
233
+
234
+
212
235
  it "should return data if no of the above" do
213
- RestClient::Payload.generate("data").should be_kind_of(RestClient::Payload::Base)
236
+ expect(RestClient::Payload.generate("data")).to be_kind_of(RestClient::Payload::Base)
214
237
  end
215
238
 
216
239
  it "should recognize nested multipart payloads in hashes" do
217
240
  f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
218
- RestClient::Payload.generate({"foo" => {"file" => f}}).should be_kind_of(RestClient::Payload::Multipart)
241
+ expect(RestClient::Payload.generate({"foo" => {"file" => f}})).to be_kind_of(RestClient::Payload::Multipart)
219
242
  end
220
243
 
221
244
  it "should recognize nested multipart payloads in arrays" do
222
245
  f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
223
- RestClient::Payload.generate({"foo" => [f]}).should be_kind_of(RestClient::Payload::Multipart)
246
+ expect(RestClient::Payload.generate({"foo" => [f]})).to be_kind_of(RestClient::Payload::Multipart)
224
247
  end
225
248
 
226
249
  it "should recognize file payloads that can be streamed" do
227
250
  f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
228
- RestClient::Payload.generate(f).should be_kind_of(RestClient::Payload::Streamed)
251
+ expect(RestClient::Payload.generate(f)).to be_kind_of(RestClient::Payload::Streamed)
229
252
  end
230
253
 
231
254
  it "should recognize other payloads that can be streamed" do
232
- RestClient::Payload.generate(StringIO.new('foo')).should be_kind_of(RestClient::Payload::Streamed)
255
+ expect(RestClient::Payload.generate(StringIO.new('foo'))).to be_kind_of(RestClient::Payload::Streamed)
233
256
  end
234
257
 
235
258
  # hashery gem introduces Hash#read convenience method. Existence of #read method used to determine of content is streameable :/
236
259
  it "shouldn't treat hashes as streameable" do
237
- RestClient::Payload.generate({"foo" => 'bar'}).should be_kind_of(RestClient::Payload::UrlEncoded)
260
+ expect(RestClient::Payload.generate({"foo" => 'bar'})).to be_kind_of(RestClient::Payload::UrlEncoded)
238
261
  end
239
262
  end
240
-
241
- class HashMapForTesting < Hash
242
- alias :read :[]
243
- end
244
263
  end