rest-client 1.6.14 → 2.0.2

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 (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