Merged updates from trunk into stable branch
[feedcatcher.git] / vendor / rails / actionpack / test / controller / request / multipart_params_parsing_test.rb
1 require 'abstract_unit'
2
3 class MultipartParamsParsingTest < ActionController::IntegrationTest
4 class TestController < ActionController::Base
5 class << self
6 attr_accessor :last_request_parameters
7 end
8
9 def parse
10 self.class.last_request_parameters = request.request_parameters
11 head :ok
12 end
13
14 def read
15 render :text => "File: #{params[:uploaded_data].read}"
16 end
17 end
18
19 FIXTURE_PATH = File.dirname(__FILE__) + '/../../fixtures/multipart'
20
21 def teardown
22 TestController.last_request_parameters = nil
23 end
24
25 test "parses single parameter" do
26 assert_equal({ 'foo' => 'bar' }, parse_multipart('single_parameter'))
27 end
28
29 test "parses bracketed parameters" do
30 assert_equal({ 'foo' => { 'baz' => 'bar'}}, parse_multipart('bracketed_param'))
31 end
32
33 test "parses text file" do
34 params = parse_multipart('text_file')
35 assert_equal %w(file foo), params.keys.sort
36 assert_equal 'bar', params['foo']
37
38 file = params['file']
39 assert_kind_of Tempfile, file
40 assert_equal 'file.txt', file.original_filename
41 assert_equal "text/plain", file.content_type
42 assert_equal 'contents', file.read
43 end
44
45 test "parses boundary problem file" do
46 params = parse_multipart('boundary_problem_file')
47 assert_equal %w(file foo), params.keys.sort
48
49 file = params['file']
50 foo = params['foo']
51
52 assert_kind_of Tempfile, file
53
54 assert_equal 'file.txt', file.original_filename
55 assert_equal "text/plain", file.content_type
56
57 assert_equal 'bar', foo
58 end
59
60 test "parses large text file" do
61 params = parse_multipart('large_text_file')
62 assert_equal %w(file foo), params.keys.sort
63 assert_equal 'bar', params['foo']
64
65 file = params['file']
66
67 assert_kind_of Tempfile, file
68
69 assert_equal 'file.txt', file.original_filename
70 assert_equal "text/plain", file.content_type
71 assert ('a' * 20480) == file.read
72 end
73
74 test "parses binary file" do
75 params = parse_multipart('binary_file')
76 assert_equal %w(file flowers foo), params.keys.sort
77 assert_equal 'bar', params['foo']
78
79 file = params['file']
80 assert_kind_of Tempfile, file
81 assert_equal 'file.csv', file.original_filename
82 assert_nil file.content_type
83 assert_equal 'contents', file.read
84
85 file = params['flowers']
86 assert_kind_of Tempfile, file
87 assert_equal 'flowers.jpg', file.original_filename
88 assert_equal "image/jpeg", file.content_type
89 assert_equal 19512, file.size
90 end
91
92 test "parses mixed files" do
93 params = parse_multipart('mixed_files')
94 assert_equal %w(files foo), params.keys.sort
95 assert_equal 'bar', params['foo']
96
97 # Ruby CGI doesn't handle multipart/mixed for us.
98 files = params['files']
99 assert_kind_of String, files
100 files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding)
101 assert_equal 19756, files.size
102 end
103
104 test "does not create tempfile if no file has been selected" do
105 params = parse_multipart('none')
106 assert_equal %w(submit-name), params.keys.sort
107 assert_equal 'Larry', params['submit-name']
108 assert_equal nil, params['files']
109 end
110
111 test "parses empty upload file" do
112 params = parse_multipart('empty')
113 assert_equal %w(files submit-name), params.keys.sort
114 assert_equal 'Larry', params['submit-name']
115 assert params['files']
116 assert_equal "", params['files'].read
117 end
118
119 test "uploads and reads binary file" do
120 with_test_routing do
121 fixture = FIXTURE_PATH + "/mona_lisa.jpg"
122 params = { :uploaded_data => fixture_file_upload(fixture, "image/jpg") }
123 post '/read', params
124 expected_length = 'File: '.length + File.size(fixture)
125 assert_equal expected_length, response.content_length
126 end
127 end
128
129 test "uploads and reads file" do
130 with_test_routing do
131 post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain")
132 assert_equal "File: Hello", response.body
133 end
134 end
135
136 # The lint wrapper is used in integration tests
137 # instead of a normal StringIO class
138 InputWrapper = Rack::Lint::InputWrapper
139
140 test "parses unwindable stream" do
141 InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE)
142 params = parse_multipart('large_text_file')
143 assert_equal %w(file foo), params.keys.sort
144 assert_equal 'bar', params['foo']
145 end
146
147 test "uploads and reads file with unwindable input" do
148 InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE)
149
150 with_test_routing do
151 post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain")
152 assert_equal "File: Hello", response.body
153 end
154 end
155
156 test "passes through rack middleware and uploads file" do
157 with_muck_middleware do
158 with_test_routing do
159 post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain")
160 assert_equal "File: Hello", response.body
161 end
162 end
163 end
164
165 test "passes through rack middleware and uploads file with unwindable input" do
166 InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE)
167
168 with_muck_middleware do
169 with_test_routing do
170 post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain")
171 assert_equal "File: Hello", response.body
172 end
173 end
174 end
175
176 private
177 def fixture(name)
178 File.open(File.join(FIXTURE_PATH, name), 'rb') do |file|
179 { "rack.input" => file.read,
180 "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
181 "CONTENT_LENGTH" => file.stat.size.to_s }
182 end
183 end
184
185 def parse_multipart(name)
186 with_test_routing do
187 headers = fixture(name)
188 post "/parse", headers.delete("rack.input"), headers
189 assert_response :ok
190 TestController.last_request_parameters
191 end
192 end
193
194 def with_test_routing
195 with_routing do |set|
196 set.draw do |map|
197 map.connect ':action', :controller => "multipart_params_parsing_test/test"
198 end
199 yield
200 end
201 end
202
203 class MuckMiddleware
204 def initialize(app)
205 @app = app
206 end
207
208 def call(env)
209 req = Rack::Request.new(env)
210 req.params # Parse params
211 @app.call(env)
212 end
213 end
214
215 def with_muck_middleware
216 original_middleware = ActionController::Dispatcher.middleware
217 middleware = original_middleware.dup
218 middleware.insert_after ActionController::RewindableInput, MuckMiddleware
219 ActionController::Dispatcher.middleware = middleware
220 yield
221 ActionController::Dispatcher.middleware = original_middleware
222 end
223 end