koala 1.0.0.beta → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG +17 -3
  3. data/Gemfile +3 -0
  4. data/LICENSE +1 -1
  5. data/Manifest +5 -2
  6. data/Rakefile +13 -14
  7. data/koala.gemspec +35 -20
  8. data/lib/koala/graph_api.rb +183 -131
  9. data/lib/koala/http_services.rb +46 -55
  10. data/lib/koala/test_users.rb +21 -8
  11. data/lib/koala/uploadable_io.rb +115 -0
  12. data/lib/koala.rb +52 -84
  13. data/readme.md +19 -6
  14. data/spec/cases/api_base_spec.rb +101 -0
  15. data/spec/cases/graph_and_rest_api_spec.rb +31 -0
  16. data/spec/cases/graph_api_spec.rb +25 -0
  17. data/spec/cases/http_services/http_service_spec.rb +54 -0
  18. data/spec/cases/http_services/net_http_service_spec.rb +350 -0
  19. data/spec/cases/http_services/typhoeus_service_spec.rb +144 -0
  20. data/spec/cases/oauth_spec.rb +409 -0
  21. data/spec/cases/realtime_updates_spec.rb +184 -0
  22. data/spec/cases/rest_api_spec.rb +25 -0
  23. data/spec/{koala/test_users/test_users_tests.rb → cases/test_users_spec.rb} +46 -33
  24. data/spec/cases/uploadable_io_spec.rb +151 -0
  25. data/spec/{facebook_data.yml → fixtures/facebook_data.yml} +12 -14
  26. data/spec/{mock_facebook_responses.yml → fixtures/mock_facebook_responses.yml} +313 -306
  27. data/spec/spec_helper.rb +18 -0
  28. data/spec/support/graph_api_shared_examples.rb +424 -0
  29. data/spec/{koala → support}/live_testing_data_helper.rb +39 -42
  30. data/spec/{mock_http_service.rb → support/mock_http_service.rb} +94 -95
  31. data/spec/{koala/rest_api/rest_api_tests.rb → support/rest_api_shared_examples.rb} +43 -0
  32. data/spec/support/setup_mocks_or_live.rb +52 -0
  33. data/spec/support/uploadable_io_shared_examples.rb +76 -0
  34. metadata +107 -48
  35. data/init.rb +0 -2
  36. data/spec/koala/api_base_tests.rb +0 -102
  37. data/spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb +0 -14
  38. data/spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb +0 -16
  39. data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +0 -63
  40. data/spec/koala/graph_api/graph_api_tests.rb +0 -86
  41. data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +0 -154
  42. data/spec/koala/graph_api/graph_collection_tests.rb +0 -104
  43. data/spec/koala/net_http_service_tests.rb +0 -430
  44. data/spec/koala/oauth/oauth_tests.rb +0 -409
  45. data/spec/koala/realtime_updates/realtime_updates_tests.rb +0 -187
  46. data/spec/koala/rest_api/rest_api_no_access_token_tests.rb +0 -25
  47. data/spec/koala/rest_api/rest_api_with_access_token_tests.rb +0 -38
  48. data/spec/koala/typhoeus_service_tests.rb +0 -156
  49. data/spec/koala_spec.rb +0 -18
  50. data/spec/koala_spec_helper.rb +0 -70
  51. data/spec/koala_spec_without_mocks.rb +0 -19
  52. /data/spec/{koala/assets → fixtures}/beach.jpg +0 -0
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::API" do
4
+ before(:each) do
5
+ @service = Koala::Facebook::API.new
6
+ end
7
+
8
+ it "should not include an access token if none was given" do
9
+ Koala.should_receive(:make_request).with(
10
+ anything,
11
+ hash_not_including('access_token' => 1),
12
+ anything,
13
+ anything
14
+ ).and_return(Koala::Response.new(200, "", ""))
15
+
16
+ @service.api('anything')
17
+ end
18
+
19
+ it "should include an access token if given" do
20
+ token = 'adfadf'
21
+ service = Koala::Facebook::API.new token
22
+
23
+ Koala.should_receive(:make_request).with(
24
+ anything,
25
+ hash_including('access_token' => token),
26
+ anything,
27
+ anything
28
+ ).and_return(Koala::Response.new(200, "", ""))
29
+
30
+ service.api('anything')
31
+ end
32
+
33
+ it "should have an attr_reader for access token" do
34
+ token = 'adfadf'
35
+ service = Koala::Facebook::API.new token
36
+ service.access_token.should == token
37
+ end
38
+
39
+ it "should get the attribute of a Koala::Response given by the http_component parameter" do
40
+ http_component = :method_name
41
+
42
+ response = mock('Mock KoalaResponse', :body => '', :status => 200)
43
+ response.should_receive(http_component).and_return('')
44
+
45
+ Koala.stub(:make_request).and_return(response)
46
+
47
+ @service.api('anything', 'get', {}, :http_component => http_component)
48
+ end
49
+
50
+ it "should return the body of the request as JSON if no http_component is given" do
51
+ response = stub('response', :body => 'body', :status => 200)
52
+ Koala.stub(:make_request).and_return(response)
53
+
54
+ json_body = mock('JSON body')
55
+ JSON.stub(:parse).and_return([json_body])
56
+
57
+ @service.api('anything').should == json_body
58
+ end
59
+
60
+ it "should execute a block with the response body if passed one" do
61
+ body = '{}'
62
+ Koala.stub(:make_request).and_return(Koala::Response.new(200, body, {}))
63
+
64
+ yield_test = mock('Yield Tester')
65
+ yield_test.should_receive(:pass)
66
+
67
+ @service.api('anything') do |arg|
68
+ yield_test.pass
69
+ arg.should == JSON.parse(body)
70
+ end
71
+ end
72
+
73
+ it "should raise an API error if the HTTP response code is greater than or equal to 500" do
74
+ Koala.stub(:make_request).and_return(Koala::Response.new(500, 'response body', {}))
75
+
76
+ lambda { @service.api('anything') }.should raise_exception(Koala::Facebook::APIError)
77
+ end
78
+
79
+ it "should handle rogue true/false as responses" do
80
+ Koala.should_receive(:make_request).and_return(Koala::Response.new(200, 'true', {}))
81
+ @service.api('anything').should be_true
82
+
83
+ Koala.should_receive(:make_request).and_return(Koala::Response.new(200, 'false', {}))
84
+ @service.api('anything').should be_false
85
+ end
86
+
87
+ describe "with regard to leading slashes" do
88
+ it "should add a leading / to the path if not present" do
89
+ path = "anything"
90
+ Koala.should_receive(:make_request).with("/#{path}", anything, anything, anything).and_return(Koala::Response.new(200, 'true', {}))
91
+ @service.api(path)
92
+ end
93
+
94
+ it "shouldn't change the path if a leading / is present" do
95
+ path = "/anything"
96
+ Koala.should_receive(:make_request).with(path, anything, anything, anything).and_return(Koala::Response.new(200, 'true', {}))
97
+ @service.api(path)
98
+ end
99
+ end
100
+
101
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::GraphAndRestAPI" do
4
+ include LiveTestingDataHelper
5
+
6
+ describe "with an access token" do
7
+ before(:each) do
8
+ @api = Koala::Facebook::GraphAndRestAPI.new(@token)
9
+ end
10
+
11
+ it_should_behave_like "Koala RestAPI"
12
+ it_should_behave_like "Koala RestAPI with an access token"
13
+
14
+ it_should_behave_like "Koala GraphAPI"
15
+ it_should_behave_like "Koala GraphAPI with an access token"
16
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
17
+ end
18
+
19
+ describe "without an access token" do
20
+ before(:each) do
21
+ @api = Koala::Facebook::GraphAndRestAPI.new
22
+ end
23
+
24
+ it_should_behave_like "Koala RestAPI"
25
+ it_should_behave_like "Koala RestAPI without an access token"
26
+
27
+ it_should_behave_like "Koala GraphAPI"
28
+ it_should_behave_like "Koala GraphAPI without an access token"
29
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Koala::Facebook::GraphAPI" do
4
+ include LiveTestingDataHelper
5
+
6
+ context "with an access token" do
7
+ before :each do
8
+ @api = Koala::Facebook::GraphAPI.new(@token)
9
+ end
10
+
11
+ it_should_behave_like "Koala GraphAPI"
12
+ it_should_behave_like "Koala GraphAPI with an access token"
13
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
14
+ end
15
+
16
+ context "without an access token" do
17
+ before :each do
18
+ @api = Koala::Facebook::GraphAPI.new
19
+ end
20
+
21
+ it_should_behave_like "Koala GraphAPI"
22
+ it_should_behave_like "Koala GraphAPI without an access token"
23
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
24
+ end
25
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ class Bear
5
+ include Koala::HTTPService
6
+ end
7
+
8
+ describe "Koala::HTTPService" do
9
+
10
+ describe "common methods" do
11
+ describe "always_use_ssl accessor" do
12
+ it "should be added" do
13
+ # in Ruby 1.8, .methods returns strings
14
+ # in Ruby 1.9, .method returns symbols
15
+ Bear.methods.collect {|m| m.to_sym}.should include(:always_use_ssl)
16
+ Bear.methods.collect {|m| m.to_sym}.should include(:always_use_ssl=)
17
+ end
18
+ end
19
+
20
+ describe "server" do
21
+ describe "without options[:beta]" do
22
+ it "should return the rest server if options[:rest_api]" do
23
+ Bear.server(:rest_api => true).should == Koala::Facebook::REST_SERVER
24
+ end
25
+
26
+ it "should return the rest server if !options[:rest_api]" do
27
+ Bear.server(:rest_api => false).should == Koala::Facebook::GRAPH_SERVER
28
+ Bear.server({}).should == Koala::Facebook::GRAPH_SERVER
29
+ end
30
+ end
31
+
32
+ describe "without options[:beta]" do
33
+ before :each do
34
+ @options = {:beta => true}
35
+ end
36
+
37
+ it "should return the rest server if options[:rest_api]" do
38
+ server = Bear.server(@options.merge(:rest_api => true))
39
+ server.should =~ Regexp.new(Koala::Facebook::REST_SERVER)
40
+ server.should =~ /beta\./
41
+ end
42
+
43
+ it "should return the rest server if !options[:rest_api]" do
44
+ server = Bear.server(:beta => true)
45
+ server.should =~ Regexp.new(Koala::Facebook::GRAPH_SERVER)
46
+ server.should =~ /beta\./
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,350 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ module Horse
5
+ include Koala::NetHTTPService
6
+ end
7
+
8
+ describe "NetHTTPService module holder class Horse" do
9
+ before :each do
10
+ # reset the always_use_ssl parameter
11
+ Horse.always_use_ssl = nil
12
+ end
13
+
14
+ it "should define a make_request static module method" do
15
+ Horse.respond_to?(:make_request).should be_true
16
+ end
17
+
18
+ it "should include the Koala::HTTPService module defining common features" do
19
+ Horse.included_modules.include?(Koala::HTTPService).should be_true
20
+ end
21
+
22
+ describe "when making a request" do
23
+ before(:each) do
24
+ # Setup stubs for make_request to execute without exceptions
25
+ @mock_http_response = stub('Net::HTTPResponse', :code => 1)
26
+ @mock_body = stub('Net::HTTPResponse body')
27
+ @http_request_result = [@mock_http_response, @mock_body]
28
+
29
+ # to_ary is called in Ruby 1.9 to provide backwards compatibility
30
+ # with the response, body = http.get() syntax we use
31
+ @mock_http_response.stub!(:to_ary).and_return(@http_request_result)
32
+
33
+ @http_yield_mock = mock('Net::HTTP start yielded object')
34
+
35
+ @http_yield_mock.stub(:post).and_return(@http_request_result)
36
+ @http_yield_mock.stub(:get).and_return(@http_request_result)
37
+
38
+ @http_mock = stub('Net::HTTP object', 'use_ssl=' => true, 'verify_mode=' => true)
39
+ @http_mock.stub(:start).and_yield(@http_yield_mock)
40
+
41
+ Net::HTTP.stub(:new).and_return(@http_mock)
42
+ end
43
+
44
+ describe "the connection" do
45
+ it "should use POST if verb is not GET" do
46
+ @http_yield_mock.should_receive(:post).and_return(@mock_http_response)
47
+ @http_mock.should_receive(:start).and_yield(@http_yield_mock)
48
+
49
+ Horse.make_request('anything', {}, 'anything')
50
+ end
51
+
52
+ it "should use GET if that verb is specified" do
53
+ @http_yield_mock.should_receive(:get).and_return(@mock_http_response)
54
+ @http_mock.should_receive(:start).and_yield(@http_yield_mock)
55
+
56
+ Horse.make_request('anything', {}, 'get')
57
+ end
58
+
59
+ it "should add the method to the arguments if it's not get or post" do
60
+ args = {}
61
+ method = "telekenesis"
62
+ # since the arguments get encoded later, we'll test for merge!
63
+ # even though that's somewhat testing internal implementation
64
+ args.should_receive(:merge!).with(:method => method)
65
+
66
+ Horse.make_request('anything', args, method)
67
+ end
68
+ end
69
+
70
+ describe "if the request has an access token" do
71
+ before :each do
72
+ @args = {"access_token" => "123"}
73
+ end
74
+
75
+ it "should use SSL" do
76
+ @http_mock.should_receive('use_ssl=').with(true)
77
+
78
+ Horse.make_request('anything', @args, 'anything')
79
+ end
80
+
81
+ it "should set the port to 443" do
82
+ Net::HTTP.should_receive(:new).with(anything, 443).and_return(@http_mock)
83
+
84
+ Horse.make_request('anything', @args, 'anything')
85
+ end
86
+ end
87
+
88
+ describe "if always_use_ssl is true" do
89
+ before :each do
90
+ Horse.always_use_ssl = true
91
+ end
92
+
93
+ it "should use SSL" do
94
+ @http_mock.should_receive('use_ssl=').with(true)
95
+
96
+ Horse.make_request('anything', {}, 'anything')
97
+ end
98
+
99
+ it "should set the port to 443" do
100
+ Net::HTTP.should_receive(:new).with(anything, 443).and_return(@http_mock)
101
+
102
+ Horse.make_request('anything', {}, 'anything')
103
+ end
104
+ end
105
+
106
+ describe "if the use_ssl option is provided" do
107
+ it "should use SSL" do
108
+ @http_mock.should_receive('use_ssl=').with(true)
109
+
110
+ Horse.make_request('anything', {}, 'anything', :use_ssl => true)
111
+ end
112
+
113
+ it "should set the port to 443" do
114
+ Net::HTTP.should_receive(:new).with(anything, 443).and_return(@http_mock)
115
+
116
+ Horse.make_request('anything', {}, 'anything', :use_ssl => true)
117
+ end
118
+ end
119
+
120
+ describe "if there's no token and always_use_ssl isn't true" do
121
+ it "should not use SSL" do
122
+ @http_mock.should_not_receive('use_ssl=')
123
+ Horse.make_request('anything', {}, 'anything')
124
+ end
125
+
126
+ it "should not set the port" do
127
+ Net::HTTP.should_receive(:new).with(anything, nil).and_return(@http_mock)
128
+ Horse.make_request('anything', {}, 'anything')
129
+ end
130
+ end
131
+
132
+ it "should use the graph server by default" do
133
+ Net::HTTP.should_receive(:new).with(Koala::Facebook::GRAPH_SERVER, anything).and_return(@http_mock)
134
+ Horse.make_request('anything', {}, 'anything')
135
+ end
136
+
137
+ it "should use the REST server if the :rest_api option is true" do
138
+ Net::HTTP.should_receive(:new).with(Koala::Facebook::REST_SERVER, anything).and_return(@http_mock)
139
+ Horse.make_request('anything', {}, 'anything', :rest_api => true)
140
+ end
141
+
142
+ it "no longer sets verify_mode to no verification" do
143
+ @http_mock.should_not_receive('verify_mode=')
144
+
145
+ Horse.make_request('anything', {}, 'anything')
146
+ end
147
+
148
+ it "should start an HTTP connection" do
149
+ @http_mock.should_receive(:start).and_yield(@http_yield_mock)
150
+ Horse.make_request('anything', {}, 'anything')
151
+ end
152
+
153
+ it 'creates a HTTP Proxy object when options contain a proxy' do
154
+ Net::HTTP.should_receive(:new).with(anything, anything, 'proxy', 1234, 'user', 'pass').and_return(@http_mock)
155
+ Horse.make_request('anything', {}, 'anything', {:proxy => 'http://user:pass@proxy:1234'})
156
+ end
157
+
158
+ it 'sets both timeouts when options contains a timeout' do
159
+ @http_mock.should_receive(:open_timeout=).with(10)
160
+ @http_mock.should_receive(:read_timeout=).with(10)
161
+ Horse.make_request('anything', {}, 'anything', {:timeout => 10})
162
+ end
163
+
164
+ describe "via POST" do
165
+ it "should use Net::HTTP to make a POST request" do
166
+ @http_yield_mock.should_receive(:post).and_return(@http_request_result)
167
+
168
+ Horse.make_request('anything', {}, 'post')
169
+ end
170
+
171
+ it "should go to the specified path adding a / if it doesn't exist" do
172
+ path = mock('Path')
173
+ @http_yield_mock.should_receive(:post).with(path, anything).and_return(@http_request_result)
174
+
175
+ Horse.make_request(path, {}, 'post')
176
+ end
177
+
178
+ it "should use encoded parameters" do
179
+ args = {}
180
+ params = mock('Encoded parameters')
181
+ Horse.should_receive(:encode_params).with(args).and_return(params)
182
+
183
+ @http_yield_mock.should_receive(:post).with(anything, params).and_return(@http_request_result)
184
+
185
+ Horse.make_request('anything', args, 'post')
186
+ end
187
+
188
+ describe "with multipart/form-data" do
189
+ before(:each) do
190
+ Horse.stub(:encode_multipart_params)
191
+ Horse.stub("params_require_multipart?").and_return(true)
192
+
193
+ @multipart_request_stub = stub('Stub Multipart Request')
194
+ Net::HTTP::Post::Multipart.stub(:new).and_return(@multipart_request_stub)
195
+
196
+ @file_stub = stub('fake File', "kind_of?" => true, "path" => 'anypath.jpg')
197
+
198
+ @http_yield_mock.stub(:request).with(@multipart_request_stub).and_return(@http_request_result)
199
+ end
200
+
201
+ it "should use multipart/form-data if any parameter is a valid file hash" do
202
+ @http_yield_mock.should_receive(:request).with(@multipart_request_stub).and_return(@http_request_result)
203
+
204
+ Horse.make_request('anything', {}, 'post')
205
+ end
206
+
207
+ it "should use the given request path for the request" do
208
+ args = {"file" => @file_stub}
209
+ expected_path = 'expected/path'
210
+
211
+ Net::HTTP::Post::Multipart.should_receive(:new).with(expected_path, anything).and_return(@multipart_request_stub)
212
+
213
+ Horse.make_request(expected_path, {}, 'post')
214
+ end
215
+
216
+ it "should use multipart encoded arguments for the request" do
217
+ args = {"file" => @file_stub}
218
+ expected_params = stub('Stub Multipart Params')
219
+
220
+ Horse.should_receive(:encode_multipart_params).with(args).and_return(expected_params)
221
+ Net::HTTP::Post::Multipart.should_receive(:new).with(anything, expected_params).and_return(@multipart_request_stub)
222
+
223
+ Horse.make_request('anything', args, 'post')
224
+ end
225
+ end
226
+ end
227
+
228
+ describe "via GET" do
229
+ it "should use Net::HTTP to make a GET request" do
230
+ @http_yield_mock.should_receive(:get).and_return(@http_request_result)
231
+
232
+ Horse.make_request('anything', {}, 'get')
233
+ end
234
+
235
+ it "should use the correct path, including arguments" do
236
+ path = mock('Path')
237
+ params = mock('Encoded parameters')
238
+ args = {}
239
+
240
+ Horse.should_receive(:encode_params).with(args).and_return(params)
241
+ @http_yield_mock.should_receive(:get).with("#{path}?#{params}").and_return(@http_request_result)
242
+
243
+ Horse.make_request(path, args, 'get')
244
+ end
245
+ end
246
+
247
+ describe "the returned value" do
248
+ before(:each) do
249
+ @response = Horse.make_request('anything', {}, 'anything')
250
+ end
251
+
252
+ it "should return a Koala::Response object" do
253
+ @response.class.should == Koala::Response
254
+ end
255
+
256
+ it "should return a Koala::Response with the right status" do
257
+ @response.status.should == @mock_http_response.code
258
+ end
259
+
260
+ it "should reutrn a Koala::Response with the right body" do
261
+ @response.body.should == @mock_body
262
+ end
263
+
264
+ it "should return a Koala::Response with the Net::HTTPResponse object as headers" do
265
+ @response.headers.should == @mock_http_response
266
+ end
267
+ end # describe return value
268
+ end # describe when making a request
269
+
270
+ describe "when encoding parameters" do
271
+ it "should return an empty string if param_hash evaluates to false" do
272
+ Horse.encode_params(nil).should == ''
273
+ end
274
+
275
+ it "should convert values to JSON if the value is not a String" do
276
+ val = 'json_value'
277
+ not_a_string = 'not_a_string'
278
+ not_a_string.stub(:class).and_return('NotAString')
279
+ not_a_string.should_receive(:to_json).and_return(val)
280
+
281
+ string = "hi"
282
+
283
+ args = {
284
+ not_a_string => not_a_string,
285
+ string => string
286
+ }
287
+
288
+ result = Horse.encode_params(args)
289
+ result.split('&').find do |key_and_val|
290
+ key_and_val.match("#{not_a_string}=#{val}")
291
+ end.should be_true
292
+ end
293
+
294
+ it "should escape all values" do
295
+ args = Hash[*(1..4).map {|i| [i.to_s, "Value #{i}($"]}.flatten]
296
+
297
+ result = Horse.encode_params(args)
298
+ result.split('&').each do |key_val|
299
+ key, val = key_val.split('=')
300
+ val.should == CGI.escape(args[key])
301
+ end
302
+ end
303
+
304
+ it "should convert all keys to Strings" do
305
+ args = Hash[*(1..4).map {|i| [i, "val#{i}"]}.flatten]
306
+
307
+ result = Horse.encode_params(args)
308
+ result.split('&').each do |key_val|
309
+ key, val = key_val.split('=')
310
+ key.should == args.find{|key_val_arr| key_val_arr.last == val}.first.to_s
311
+ end
312
+ end
313
+ end
314
+
315
+ describe "when detecting if multipart posting is needed" do
316
+ it "should be true if any parameter value requires multipart post" do
317
+ koala_io = mock("Koala::IO")
318
+ koala_io.should_receive(:kind_of?).with(Koala::UploadableIO).and_return(true)
319
+
320
+ args = {
321
+ "key1" => "val",
322
+ "key2" => "val",
323
+ "key3" => koala_io,
324
+ "key4" => "val"
325
+ }
326
+
327
+ Horse.params_require_multipart?(args).should be_true
328
+ end
329
+
330
+ describe "when encoding multipart/form-data params" do
331
+ it "should replace Koala::UploadableIO values with UploadIO values" do
332
+ upload_io = UploadIO.new(__FILE__, "fake type")
333
+
334
+ uploadable_io = stub('Koala::UploadableIO')
335
+ uploadable_io.should_receive(:kind_of?).with(Koala::UploadableIO).and_return(true)
336
+ uploadable_io.should_receive(:to_upload_io).and_return(upload_io)
337
+ args = {
338
+ "not_a_file" => "not a file",
339
+ "file" => uploadable_io
340
+ }
341
+
342
+ result = Horse.encode_multipart_params(args)
343
+
344
+ result["not_a_file"] == args["not_a_file"]
345
+ result["file"] == upload_io
346
+ end
347
+ end
348
+
349
+ end
350
+ end