darkhelmet-sinatra 0.9.1.1 → 0.10.1

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 (88) hide show
  1. data/AUTHORS +2 -0
  2. data/CHANGES +180 -0
  3. data/LICENSE +1 -1
  4. data/README.jp.rdoc +552 -0
  5. data/README.rdoc +177 -38
  6. data/Rakefile +18 -25
  7. data/lib/sinatra.rb +1 -2
  8. data/lib/sinatra/base.rb +405 -305
  9. data/lib/sinatra/main.rb +5 -24
  10. data/lib/sinatra/showexceptions.rb +303 -0
  11. data/lib/sinatra/tilt.rb +509 -0
  12. data/sinatra.gemspec +21 -51
  13. data/test/base_test.rb +123 -93
  14. data/test/builder_test.rb +2 -1
  15. data/test/contest.rb +64 -0
  16. data/test/erb_test.rb +1 -1
  17. data/test/erubis_test.rb +82 -0
  18. data/test/extensions_test.rb +24 -8
  19. data/test/filter_test.rb +99 -3
  20. data/test/haml_test.rb +25 -3
  21. data/test/helper.rb +43 -48
  22. data/test/helpers_test.rb +500 -424
  23. data/test/mapped_error_test.rb +163 -137
  24. data/test/middleware_test.rb +3 -3
  25. data/test/request_test.rb +16 -1
  26. data/test/response_test.rb +2 -2
  27. data/test/result_test.rb +1 -1
  28. data/test/route_added_hook_test.rb +59 -0
  29. data/test/routing_test.rb +170 -22
  30. data/test/sass_test.rb +44 -1
  31. data/test/server_test.rb +19 -13
  32. data/test/sinatra_test.rb +1 -1
  33. data/test/static_test.rb +9 -2
  34. data/test/templates_test.rb +78 -11
  35. data/test/views/error.builder +3 -0
  36. data/test/views/error.erb +3 -0
  37. data/test/views/error.erubis +3 -0
  38. data/test/views/error.haml +3 -0
  39. data/test/views/error.sass +2 -0
  40. data/test/views/foo/hello.test +1 -0
  41. data/test/views/hello.erubis +1 -0
  42. data/test/views/layout2.erubis +2 -0
  43. metadata +37 -55
  44. data/compat/app_test.rb +0 -282
  45. data/compat/application_test.rb +0 -262
  46. data/compat/builder_test.rb +0 -101
  47. data/compat/compat_test.rb +0 -12
  48. data/compat/custom_error_test.rb +0 -62
  49. data/compat/erb_test.rb +0 -136
  50. data/compat/events_test.rb +0 -78
  51. data/compat/filter_test.rb +0 -30
  52. data/compat/haml_test.rb +0 -233
  53. data/compat/helper.rb +0 -30
  54. data/compat/mapped_error_test.rb +0 -72
  55. data/compat/pipeline_test.rb +0 -45
  56. data/compat/public/foo.xml +0 -1
  57. data/compat/sass_test.rb +0 -57
  58. data/compat/sessions_test.rb +0 -42
  59. data/compat/streaming_test.rb +0 -133
  60. data/compat/sym_params_test.rb +0 -19
  61. data/compat/template_test.rb +0 -30
  62. data/compat/use_in_file_templates_test.rb +0 -47
  63. data/compat/views/foo.builder +0 -1
  64. data/compat/views/foo.erb +0 -1
  65. data/compat/views/foo.haml +0 -1
  66. data/compat/views/foo.sass +0 -2
  67. data/compat/views/foo_layout.erb +0 -2
  68. data/compat/views/foo_layout.haml +0 -2
  69. data/compat/views/layout_test/foo.builder +0 -1
  70. data/compat/views/layout_test/foo.erb +0 -1
  71. data/compat/views/layout_test/foo.haml +0 -1
  72. data/compat/views/layout_test/foo.sass +0 -2
  73. data/compat/views/layout_test/layout.builder +0 -3
  74. data/compat/views/layout_test/layout.erb +0 -1
  75. data/compat/views/layout_test/layout.haml +0 -1
  76. data/compat/views/layout_test/layout.sass +0 -2
  77. data/compat/views/no_layout/no_layout.builder +0 -1
  78. data/compat/views/no_layout/no_layout.haml +0 -1
  79. data/lib/sinatra/compat.rb +0 -250
  80. data/lib/sinatra/test.rb +0 -126
  81. data/lib/sinatra/test/bacon.rb +0 -19
  82. data/lib/sinatra/test/rspec.rb +0 -13
  83. data/lib/sinatra/test/spec.rb +0 -11
  84. data/lib/sinatra/test/unit.rb +0 -13
  85. data/test/data/reload_app_file.rb +0 -3
  86. data/test/options_test.rb +0 -374
  87. data/test/reload_test.rb +0 -68
  88. data/test/test_test.rb +0 -144
@@ -1,497 +1,573 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
2
 
3
- describe 'Helpers#status' do
4
- before do
5
- mock_app {
6
- get '/' do
7
- status 207
8
- nil
9
- end
10
- }
11
- end
12
-
13
- it 'sets the response status code' do
14
- get '/'
15
- assert_equal 207, response.status
16
- end
17
- end
18
-
19
- describe 'Helpers#body' do
20
- it 'takes a block for defered body generation' do
21
- mock_app {
22
- get '/' do
23
- body { 'Hello World' }
24
- end
25
- }
26
-
27
- get '/'
28
- assert_equal 'Hello World', body
29
- end
30
-
31
- it 'takes a String, Array, or other object responding to #each' do
32
- mock_app {
33
- get '/' do
34
- body 'Hello World'
35
- end
36
- }
37
-
38
- get '/'
39
- assert_equal 'Hello World', body
40
- end
41
- end
42
-
43
- describe 'Helpers#redirect' do
44
- it 'uses a 302 when only a path is given' do
45
- mock_app {
46
- get '/' do
47
- redirect '/foo'
48
- fail 'redirect should halt'
49
- end
50
- }
51
-
52
- get '/'
53
- assert_equal 302, status
54
- assert_equal '', body
55
- assert_equal '/foo', response['Location']
56
- end
57
-
58
- it 'uses the code given when specified' do
59
- mock_app {
60
- get '/' do
61
- redirect '/foo', 301
62
- fail 'redirect should halt'
63
- end
64
- }
65
-
66
- get '/'
67
- assert_equal 301, status
68
- assert_equal '', body
69
- assert_equal '/foo', response['Location']
70
- end
71
-
72
- it 'redirects back to request.referer when passed back' do
73
- mock_app {
74
- get '/try_redirect' do
75
- redirect back
76
- end
77
- }
78
-
79
- request = Rack::MockRequest.new(@app)
80
- response = request.get('/try_redirect', 'HTTP_REFERER' => '/foo')
81
- assert_equal 302, response.status
82
- assert_equal '/foo', response['Location']
83
- end
84
-
85
- end
86
-
87
- describe 'Helpers#error' do
88
- it 'sets a status code and halts' do
89
- mock_app {
90
- get '/' do
91
- error 501
92
- fail 'error should halt'
93
- end
94
- }
95
-
96
- get '/'
97
- assert_equal 501, status
98
- assert_equal '', body
3
+ class HelpersTest < Test::Unit::TestCase
4
+ def test_default
5
+ assert true
99
6
  end
100
7
 
101
- it 'takes an optional body' do
102
- mock_app {
103
- get '/' do
104
- error 501, 'FAIL'
105
- fail 'error should halt'
106
- end
107
- }
108
-
109
- get '/'
110
- assert_equal 501, status
111
- assert_equal 'FAIL', body
112
- end
113
-
114
- it 'uses a 500 status code when first argument is a body' do
115
- mock_app {
116
- get '/' do
117
- error 'FAIL'
118
- fail 'error should halt'
119
- end
120
- }
121
-
122
- get '/'
123
- assert_equal 500, status
124
- assert_equal 'FAIL', body
125
- end
126
- end
127
-
128
- describe 'Helpers#not_found' do
129
- it 'halts with a 404 status' do
130
- mock_app {
131
- get '/' do
132
- not_found
133
- fail 'not_found should halt'
134
- end
135
- }
136
-
137
- get '/'
138
- assert_equal 404, status
139
- assert_equal '', body
140
- end
141
- end
142
-
143
- describe 'Helpers#headers' do
144
- it 'sets headers on the response object when given a Hash' do
145
- mock_app {
146
- get '/' do
147
- headers 'X-Foo' => 'bar', 'X-Baz' => 'bling'
148
- 'kthx'
149
- end
150
- }
8
+ describe 'status' do
9
+ setup do
10
+ mock_app {
11
+ get '/' do
12
+ status 207
13
+ nil
14
+ end
15
+ }
16
+ end
151
17
 
152
- get '/'
153
- assert ok?
154
- assert_equal 'bar', response['X-Foo']
155
- assert_equal 'bling', response['X-Baz']
156
- assert_equal 'kthx', body
18
+ it 'sets the response status code' do
19
+ get '/'
20
+ assert_equal 207, response.status
21
+ end
157
22
  end
158
23
 
159
- it 'returns the response headers hash when no hash provided' do
160
- mock_app {
161
- get '/' do
162
- headers['X-Foo'] = 'bar'
163
- 'kthx'
164
- end
165
- }
24
+ describe 'body' do
25
+ it 'takes a block for defered body generation' do
26
+ mock_app {
27
+ get '/' do
28
+ body { 'Hello World' }
29
+ end
30
+ }
166
31
 
167
- get '/'
168
- assert ok?
169
- assert_equal 'bar', response['X-Foo']
170
- end
171
- end
32
+ get '/'
33
+ assert_equal 'Hello World', body
34
+ end
172
35
 
173
- describe 'Helpers#session' do
174
- it 'uses the existing rack.session' do
175
- mock_app {
176
- get '/' do
177
- session[:foo]
178
- end
179
- }
36
+ it 'takes a String, Array, or other object responding to #each' do
37
+ mock_app {
38
+ get '/' do
39
+ body 'Hello World'
40
+ end
41
+ }
180
42
 
181
- get '/', :env => { 'rack.session' => { :foo => 'bar' } }
182
- assert_equal 'bar', body
43
+ get '/'
44
+ assert_equal 'Hello World', body
45
+ end
183
46
  end
184
47
 
185
- it 'creates a new session when none provided' do
186
- mock_app {
187
- get '/' do
188
- assert session.empty?
189
- session[:foo] = 'bar'
190
- 'Hi'
191
- end
192
- }
48
+ describe 'redirect' do
49
+ it 'uses a 302 when only a path is given' do
50
+ mock_app {
51
+ get '/' do
52
+ redirect '/foo'
53
+ fail 'redirect should halt'
54
+ end
55
+ }
56
+
57
+ get '/'
58
+ assert_equal 302, status
59
+ assert_equal '', body
60
+ assert_equal '/foo', response['Location']
61
+ end
62
+
63
+ it 'uses the code given when specified' do
64
+ mock_app {
65
+ get '/' do
66
+ redirect '/foo', 301
67
+ fail 'redirect should halt'
68
+ end
69
+ }
70
+
71
+ get '/'
72
+ assert_equal 301, status
73
+ assert_equal '', body
74
+ assert_equal '/foo', response['Location']
75
+ end
76
+
77
+ it 'redirects back to request.referer when passed back' do
78
+ mock_app {
79
+ get '/try_redirect' do
80
+ redirect back
81
+ end
82
+ }
193
83
 
194
- get '/'
195
- assert_equal 'Hi', body
84
+ request = Rack::MockRequest.new(@app)
85
+ response = request.get('/try_redirect', 'HTTP_REFERER' => '/foo')
86
+ assert_equal 302, response.status
87
+ assert_equal '/foo', response['Location']
88
+ end
196
89
  end
197
- end
198
90
 
199
- describe 'Helpers#media_type' do
200
- include Sinatra::Helpers
201
-
202
- it "looks up media types in Rack's MIME registry" do
203
- Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
204
- assert_equal 'application/foo', media_type('foo')
205
- assert_equal 'application/foo', media_type('.foo')
206
- assert_equal 'application/foo', media_type(:foo)
207
- end
91
+ describe 'error' do
92
+ it 'sets a status code and halts' do
93
+ mock_app {
94
+ get '/' do
95
+ error 501
96
+ fail 'error should halt'
97
+ end
98
+ }
99
+
100
+ get '/'
101
+ assert_equal 501, status
102
+ assert_equal '', body
103
+ end
104
+
105
+ it 'takes an optional body' do
106
+ mock_app {
107
+ get '/' do
108
+ error 501, 'FAIL'
109
+ fail 'error should halt'
110
+ end
111
+ }
112
+
113
+ get '/'
114
+ assert_equal 501, status
115
+ assert_equal 'FAIL', body
116
+ end
117
+
118
+ it 'uses a 500 status code when first argument is a body' do
119
+ mock_app {
120
+ get '/' do
121
+ error 'FAIL'
122
+ fail 'error should halt'
123
+ end
124
+ }
208
125
 
209
- it 'returns nil when given nil' do
210
- assert media_type(nil).nil?
126
+ get '/'
127
+ assert_equal 500, status
128
+ assert_equal 'FAIL', body
129
+ end
211
130
  end
212
131
 
213
- it 'returns nil when media type not registered' do
214
- assert media_type(:bizzle).nil?
215
- end
132
+ describe 'not_found' do
133
+ it 'halts with a 404 status' do
134
+ mock_app {
135
+ get '/' do
136
+ not_found
137
+ fail 'not_found should halt'
138
+ end
139
+ }
140
+
141
+ get '/'
142
+ assert_equal 404, status
143
+ assert_equal '', body
144
+ end
145
+
146
+ it 'does not set a X-Cascade header' do
147
+ mock_app {
148
+ get '/' do
149
+ not_found
150
+ fail 'not_found should halt'
151
+ end
152
+ }
216
153
 
217
- it 'returns the argument when given a media type string' do
218
- assert_equal 'text/plain', media_type('text/plain')
154
+ get '/'
155
+ assert_equal 404, status
156
+ assert_equal nil, response.headers['X-Cascade']
157
+ end
219
158
  end
220
- end
221
159
 
222
- describe 'Helpers#content_type' do
223
- it 'sets the Content-Type header' do
224
- mock_app {
225
- get '/' do
226
- content_type 'text/plain'
227
- 'Hello World'
228
- end
229
- }
160
+ describe 'headers' do
161
+ it 'sets headers on the response object when given a Hash' do
162
+ mock_app {
163
+ get '/' do
164
+ headers 'X-Foo' => 'bar', 'X-Baz' => 'bling'
165
+ 'kthx'
166
+ end
167
+ }
168
+
169
+ get '/'
170
+ assert ok?
171
+ assert_equal 'bar', response['X-Foo']
172
+ assert_equal 'bling', response['X-Baz']
173
+ assert_equal 'kthx', body
174
+ end
175
+
176
+ it 'returns the response headers hash when no hash provided' do
177
+ mock_app {
178
+ get '/' do
179
+ headers['X-Foo'] = 'bar'
180
+ 'kthx'
181
+ end
182
+ }
230
183
 
231
- get '/'
232
- assert_equal 'text/plain', response['Content-Type']
233
- assert_equal 'Hello World', body
184
+ get '/'
185
+ assert ok?
186
+ assert_equal 'bar', response['X-Foo']
187
+ end
234
188
  end
235
189
 
236
- it 'takes media type parameters (like charset=)' do
237
- mock_app {
238
- get '/' do
239
- content_type 'text/html', :charset => 'utf-8'
240
- "<h1>Hello, World</h1>"
241
- end
242
- }
243
-
244
- get '/'
245
- assert ok?
246
- assert_equal 'text/html;charset=utf-8', response['Content-Type']
247
- assert_equal "<h1>Hello, World</h1>", body
248
- end
190
+ describe 'session' do
191
+ it 'uses the existing rack.session' do
192
+ mock_app {
193
+ get '/' do
194
+ session[:foo]
195
+ end
196
+ }
249
197
 
250
- it "looks up symbols in Rack's mime types dictionary" do
251
- Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
252
- mock_app {
253
- get '/foo.xml' do
254
- content_type :foo
255
- "I AM FOO"
256
- end
257
- }
198
+ get '/', {}, { 'rack.session' => { :foo => 'bar' } }
199
+ assert_equal 'bar', body
200
+ end
258
201
 
259
- get '/foo.xml'
260
- assert ok?
261
- assert_equal 'application/foo', response['Content-Type']
262
- assert_equal 'I AM FOO', body
263
- end
202
+ it 'creates a new session when none provided' do
203
+ mock_app {
204
+ enable :sessions
264
205
 
265
- it 'fails when no mime type is registered for the argument provided' do
266
- mock_app {
267
- get '/foo.xml' do
268
- content_type :bizzle
269
- "I AM FOO"
270
- end
271
- }
272
- assert_raise(RuntimeError) { get '/foo.xml' }
273
- end
274
- end
206
+ get '/' do
207
+ assert session.empty?
208
+ session[:foo] = 'bar'
209
+ redirect '/hi'
210
+ end
275
211
 
276
- describe 'Helpers#send_file' do
277
- before do
278
- @file = File.dirname(__FILE__) + '/file.txt'
279
- File.open(@file, 'wb') { |io| io.write('Hello World') }
280
- end
212
+ get '/hi' do
213
+ "hi #{session[:foo]}"
214
+ end
215
+ }
281
216
 
282
- after do
283
- File.unlink @file
284
- @file = nil
217
+ get '/'
218
+ follow_redirect!
219
+ assert_equal 'hi bar', body
220
+ end
285
221
  end
286
222
 
287
- def send_file_app(opts={})
288
- path = @file
289
- mock_app {
290
- get '/file.txt' do
291
- send_file path, opts
292
- end
293
- }
294
- end
223
+ describe 'mime_type' do
224
+ include Sinatra::Helpers
295
225
 
296
- it "sends the contents of the file" do
297
- send_file_app
298
- get '/file.txt'
299
- assert ok?
300
- assert_equal 'Hello World', body
301
- end
226
+ it "looks up mime types in Rack's MIME registry" do
227
+ Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
228
+ assert_equal 'application/foo', mime_type('foo')
229
+ assert_equal 'application/foo', mime_type('.foo')
230
+ assert_equal 'application/foo', mime_type(:foo)
231
+ end
302
232
 
303
- it 'sets the Content-Type response header if a mime-type can be located' do
304
- send_file_app
305
- get '/file.txt'
306
- assert_equal 'text/plain', response['Content-Type']
307
- end
233
+ it 'returns nil when given nil' do
234
+ assert mime_type(nil).nil?
235
+ end
308
236
 
309
- it 'sets the Content-Length response header' do
310
- send_file_app
311
- get '/file.txt'
312
- assert_equal 'Hello World'.length.to_s, response['Content-Length']
313
- end
237
+ it 'returns nil when media type not registered' do
238
+ assert mime_type(:bizzle).nil?
239
+ end
314
240
 
315
- it 'sets the Last-Modified response header' do
316
- send_file_app
317
- get '/file.txt'
318
- assert_equal File.mtime(@file).httpdate, response['Last-Modified']
241
+ it 'returns the argument when given a media type string' do
242
+ assert_equal 'text/plain', mime_type('text/plain')
243
+ end
319
244
  end
320
245
 
321
- it "returns a 404 when not found" do
246
+ test 'Base.mime_type registers mime type' do
322
247
  mock_app {
323
- get '/' do
324
- send_file 'this-file-does-not-exist.txt'
325
- end
326
- }
327
- get '/'
328
- assert not_found?
329
- end
330
-
331
- it "does not set the Content-Disposition header by default" do
332
- send_file_app
333
- get '/file.txt'
334
- assert_nil response['Content-Disposition']
335
- end
336
-
337
- it "sets the Content-Disposition header when :disposition set to 'attachment'" do
338
- send_file_app :disposition => 'attachment'
339
- get '/file.txt'
340
- assert_equal 'attachment; filename="file.txt"', response['Content-Disposition']
341
- end
342
-
343
- it "sets the Content-Disposition header when :filename provided" do
344
- send_file_app :filename => 'foo.txt'
345
- get '/file.txt'
346
- assert_equal 'attachment; filename="foo.txt"', response['Content-Disposition']
347
- end
348
- end
248
+ mime_type :foo, 'application/foo'
349
249
 
350
- describe 'Helpers#last_modified' do
351
- before do
352
- now = Time.now
353
- mock_app {
354
250
  get '/' do
355
- body { 'Hello World' }
356
- last_modified now
357
- 'Boo!'
251
+ "foo is #{mime_type(:foo)}"
358
252
  end
359
253
  }
360
- @now = now
361
- end
362
-
363
- it 'sets the Last-Modified header to a valid RFC 2616 date value' do
364
- get '/'
365
- assert_equal @now.httpdate, response['Last-Modified']
366
- end
367
254
 
368
- it 'returns a body when conditional get misses' do
369
255
  get '/'
370
- assert_equal 200, status
371
- assert_equal 'Boo!', body
256
+ assert_equal 'foo is application/foo', body
372
257
  end
373
258
 
374
- it 'halts when a conditional GET matches' do
375
- get '/', :env => { 'HTTP_IF_MODIFIED_SINCE' => @now.httpdate }
376
- assert_equal 304, status
377
- assert_equal '', body
378
- end
379
- end
259
+ describe 'content_type' do
260
+ it 'sets the Content-Type header' do
261
+ mock_app {
262
+ get '/' do
263
+ content_type 'text/plain'
264
+ 'Hello World'
265
+ end
266
+ }
267
+
268
+ get '/'
269
+ assert_equal 'text/plain', response['Content-Type']
270
+ assert_equal 'Hello World', body
271
+ end
272
+
273
+ it 'takes media type parameters (like charset=)' do
274
+ mock_app {
275
+ get '/' do
276
+ content_type 'text/html', :charset => 'utf-8'
277
+ "<h1>Hello, World</h1>"
278
+ end
279
+ }
280
+
281
+ get '/'
282
+ assert ok?
283
+ assert_equal 'text/html;charset=utf-8', response['Content-Type']
284
+ assert_equal "<h1>Hello, World</h1>", body
285
+ end
286
+
287
+ it "looks up symbols in Rack's mime types dictionary" do
288
+ Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
289
+ mock_app {
290
+ get '/foo.xml' do
291
+ content_type :foo
292
+ "I AM FOO"
293
+ end
294
+ }
295
+
296
+ get '/foo.xml'
297
+ assert ok?
298
+ assert_equal 'application/foo', response['Content-Type']
299
+ assert_equal 'I AM FOO', body
300
+ end
301
+
302
+ it 'fails when no mime type is registered for the argument provided' do
303
+ mock_app {
304
+ get '/foo.xml' do
305
+ content_type :bizzle
306
+ "I AM FOO"
307
+ end
308
+ }
380
309
 
381
- describe 'Helpers#etag' do
382
- before do
383
- mock_app {
384
- get '/' do
385
- body { 'Hello World' }
386
- etag 'FOO'
387
- 'Boo!'
388
- end
389
- }
310
+ assert_raise(RuntimeError) { get '/foo.xml' }
311
+ end
390
312
  end
391
313
 
392
- it 'sets the ETag header' do
393
- get '/'
394
- assert_equal '"FOO"', response['ETag']
395
- end
314
+ describe 'send_file' do
315
+ setup do
316
+ @file = File.dirname(__FILE__) + '/file.txt'
317
+ File.open(@file, 'wb') { |io| io.write('Hello World') }
318
+ end
396
319
 
397
- it 'returns a body when conditional get misses' do
398
- get '/'
399
- assert_equal 200, status
400
- assert_equal 'Boo!', body
401
- end
320
+ def teardown
321
+ File.unlink @file
322
+ @file = nil
323
+ end
402
324
 
403
- it 'halts when a conditional GET matches' do
404
- get '/', :env => { 'HTTP_IF_NONE_MATCH' => '"FOO"' }
405
- assert_equal 304, status
406
- assert_equal '', body
407
- end
325
+ def send_file_app(opts={})
326
+ path = @file
327
+ mock_app {
328
+ get '/file.txt' do
329
+ send_file path, opts
330
+ end
331
+ }
332
+ end
333
+
334
+ it "sends the contents of the file" do
335
+ send_file_app
336
+ get '/file.txt'
337
+ assert ok?
338
+ assert_equal 'Hello World', body
339
+ end
340
+
341
+ it 'sets the Content-Type response header if a mime-type can be located' do
342
+ send_file_app
343
+ get '/file.txt'
344
+ assert_equal 'text/plain', response['Content-Type']
345
+ end
346
+
347
+ it 'sets the Content-Length response header' do
348
+ send_file_app
349
+ get '/file.txt'
350
+ assert_equal 'Hello World'.length.to_s, response['Content-Length']
351
+ end
352
+
353
+ it 'sets the Last-Modified response header' do
354
+ send_file_app
355
+ get '/file.txt'
356
+ assert_equal File.mtime(@file).httpdate, response['Last-Modified']
357
+ end
358
+
359
+ it "returns a 404 when not found" do
360
+ mock_app {
361
+ get '/' do
362
+ send_file 'this-file-does-not-exist.txt'
363
+ end
364
+ }
365
+ get '/'
366
+ assert not_found?
367
+ end
368
+
369
+ it "does not set the Content-Disposition header by default" do
370
+ send_file_app
371
+ get '/file.txt'
372
+ assert_nil response['Content-Disposition']
373
+ end
374
+
375
+ it "sets the Content-Disposition header when :disposition set to 'attachment'" do
376
+ send_file_app :disposition => 'attachment'
377
+ get '/file.txt'
378
+ assert_equal 'attachment; filename="file.txt"', response['Content-Disposition']
379
+ end
380
+
381
+ it "sets the Content-Disposition header when :filename provided" do
382
+ send_file_app :filename => 'foo.txt'
383
+ get '/file.txt'
384
+ assert_equal 'attachment; filename="foo.txt"', response['Content-Disposition']
385
+ end
386
+ end
387
+
388
+ describe 'cache_control' do
389
+ setup do
390
+ mock_app {
391
+ get '/' do
392
+ cache_control :public, :no_cache, :max_age => 60
393
+ 'Hello World'
394
+ end
395
+ }
396
+ end
408
397
 
409
- it 'should handle multiple ETag values in If-None-Match header' do
410
- get '/', :env => { 'HTTP_IF_NONE_MATCH' => '"BAR", *' }
411
- assert_equal 304, status
412
- assert_equal '', body
398
+ it 'sets the Cache-Control header' do
399
+ get '/'
400
+ assert_equal ['public', 'no-cache', 'max-age=60'], response['Cache-Control'].split(', ')
401
+ end
413
402
  end
414
403
 
415
- it 'uses a weak etag with the :weak option' do
416
- mock_app {
417
- get '/' do
418
- etag 'FOO', :weak
419
- "that's weak, dude."
420
- end
421
- }
422
- get '/'
423
- assert_equal 'W/"FOO"', response['ETag']
404
+ describe 'expires' do
405
+ setup do
406
+ mock_app {
407
+ get '/' do
408
+ expires 60, :public, :no_cache
409
+ 'Hello World'
410
+ end
411
+ }
412
+ end
413
+
414
+ it 'sets the Cache-Control header' do
415
+ get '/'
416
+ assert_equal ['public', 'no-cache', 'max-age=60'], response['Cache-Control'].split(', ')
417
+ end
418
+
419
+ it 'sets the Expires header' do
420
+ get '/'
421
+ assert_not_nil response['Expires']
422
+ end
423
+ end
424
+
425
+ describe 'last_modified' do
426
+ setup do
427
+ now = Time.now
428
+ mock_app {
429
+ get '/' do
430
+ body { 'Hello World' }
431
+ last_modified now
432
+ 'Boo!'
433
+ end
434
+ }
435
+ @now = now
436
+ end
437
+
438
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
439
+ get '/'
440
+ assert_equal @now.httpdate, response['Last-Modified']
441
+ end
442
+
443
+ it 'returns a body when conditional get misses' do
444
+ get '/'
445
+ assert_equal 200, status
446
+ assert_equal 'Boo!', body
447
+ end
448
+
449
+ it 'halts when a conditional GET matches' do
450
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @now.httpdate }
451
+ assert_equal 304, status
452
+ assert_equal '', body
453
+ end
454
+ end
455
+
456
+ describe 'etag' do
457
+ setup do
458
+ mock_app {
459
+ get '/' do
460
+ body { 'Hello World' }
461
+ etag 'FOO'
462
+ 'Boo!'
463
+ end
464
+ }
465
+ end
466
+
467
+ it 'sets the ETag header' do
468
+ get '/'
469
+ assert_equal '"FOO"', response['ETag']
470
+ end
471
+
472
+ it 'returns a body when conditional get misses' do
473
+ get '/'
474
+ assert_equal 200, status
475
+ assert_equal 'Boo!', body
476
+ end
477
+
478
+ it 'halts when a conditional GET matches' do
479
+ get '/', {}, { 'HTTP_IF_NONE_MATCH' => '"FOO"' }
480
+ assert_equal 304, status
481
+ assert_equal '', body
482
+ end
483
+
484
+ it 'should handle multiple ETag values in If-None-Match header' do
485
+ get '/', {}, { 'HTTP_IF_NONE_MATCH' => '"BAR", *' }
486
+ assert_equal 304, status
487
+ assert_equal '', body
488
+ end
489
+
490
+ it 'uses a weak etag with the :weak option' do
491
+ mock_app {
492
+ get '/' do
493
+ etag 'FOO', :weak
494
+ "that's weak, dude."
495
+ end
496
+ }
497
+ get '/'
498
+ assert_equal 'W/"FOO"', response['ETag']
499
+ end
424
500
  end
425
- end
426
501
 
427
- describe 'Helpers#back' do
428
- it "makes redirecting back pretty" do
429
- mock_app {
430
- get '/foo' do
431
- redirect back
432
- end
433
- }
502
+ describe 'back' do
503
+ it "makes redirecting back pretty" do
504
+ mock_app {
505
+ get '/foo' do
506
+ redirect back
507
+ end
508
+ }
434
509
 
435
- get '/foo', {}, 'HTTP_REFERER' => 'http://github.com'
436
- assert redirect?
437
- assert_equal "http://github.com", response.location
510
+ get '/foo', {}, 'HTTP_REFERER' => 'http://github.com'
511
+ assert redirect?
512
+ assert_equal "http://github.com", response.location
513
+ end
438
514
  end
439
- end
440
515
 
441
- module HelperOne; def one; '1'; end; end
442
- module HelperTwo; def two; '2'; end; end
516
+ module ::HelperOne; def one; '1'; end; end
517
+ module ::HelperTwo; def two; '2'; end; end
443
518
 
444
- describe 'Adding new helpers' do
445
- it 'takes a list of modules to mix into the app' do
446
- mock_app {
447
- helpers HelperOne, HelperTwo
519
+ describe 'Adding new helpers' do
520
+ it 'takes a list of modules to mix into the app' do
521
+ mock_app {
522
+ helpers ::HelperOne, ::HelperTwo
448
523
 
449
- get '/one' do
450
- one
451
- end
524
+ get '/one' do
525
+ one
526
+ end
452
527
 
453
- get '/two' do
454
- two
455
- end
456
- }
528
+ get '/two' do
529
+ two
530
+ end
531
+ }
457
532
 
458
- get '/one'
459
- assert_equal '1', body
533
+ get '/one'
534
+ assert_equal '1', body
460
535
 
461
- get '/two'
462
- assert_equal '2', body
463
- end
536
+ get '/two'
537
+ assert_equal '2', body
538
+ end
464
539
 
465
- it 'takes a block to mix into the app' do
466
- mock_app {
467
- helpers do
468
- def foo
469
- 'foo'
540
+ it 'takes a block to mix into the app' do
541
+ mock_app {
542
+ helpers do
543
+ def foo
544
+ 'foo'
545
+ end
470
546
  end
471
- end
472
547
 
473
- get '/' do
474
- foo
475
- end
476
- }
548
+ get '/' do
549
+ foo
550
+ end
551
+ }
477
552
 
478
- get '/'
479
- assert_equal 'foo', body
480
- end
553
+ get '/'
554
+ assert_equal 'foo', body
555
+ end
481
556
 
482
- it 'evaluates the block in class context so that methods can be aliased' do
483
- mock_app {
484
- helpers do
485
- alias_method :h, :escape_html
486
- end
557
+ it 'evaluates the block in class context so that methods can be aliased' do
558
+ mock_app {
559
+ helpers do
560
+ alias_method :h, :escape_html
561
+ end
487
562
 
488
- get '/' do
489
- h('42 < 43')
490
- end
491
- }
563
+ get '/' do
564
+ h('42 < 43')
565
+ end
566
+ }
492
567
 
493
- get '/'
494
- assert ok?
495
- assert_equal '42 &lt; 43', body
568
+ get '/'
569
+ assert ok?
570
+ assert_equal '42 &lt; 43', body
571
+ end
496
572
  end
497
573
  end