sinatra-sinatra 0.9.1.2 → 0.9.1.3

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.
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
2
 
3
- describe "Builder Templates" do
3
+ class BuilderTest < Test::Unit::TestCase
4
4
  def builder_app(&block)
5
5
  mock_app {
6
6
  set :views, File.dirname(__FILE__) + '/views'
@@ -0,0 +1,62 @@
1
+ require "test/unit"
2
+
3
+ # Test::Unit loads a default test if the suite is empty, and the only
4
+ # purpose of that test is to fail. As having empty contexts is a common
5
+ # practice, we decided to overwrite TestSuite#empty? in order to
6
+ # allow them. Having a failure when no tests have been defined seems
7
+ # counter-intuitive.
8
+ class Test::Unit::TestSuite
9
+ def empty?
10
+ false
11
+ end
12
+ end
13
+
14
+ # We added setup, test and context as class methods, and the instance
15
+ # method setup now iterates on the setup blocks. Note that all setup
16
+ # blocks must be defined with the block syntax. Adding a setup instance
17
+ # method defeats the purpose of this library.
18
+ class Test::Unit::TestCase
19
+ def self.setup(&block)
20
+ setup_blocks << block
21
+ end
22
+
23
+ def setup
24
+ self.class.setup_blocks.each do |block|
25
+ instance_eval(&block)
26
+ end
27
+ end
28
+
29
+ def self.context(name, &block)
30
+ subclass = Class.new(self.superclass)
31
+ subclass.setup_blocks.unshift(*setup_blocks)
32
+ subclass.class_eval(&block)
33
+ const_set(context_name(name), subclass)
34
+ end
35
+
36
+ def self.test(name, &block)
37
+ define_method(test_name(name), &block)
38
+ end
39
+
40
+ class << self
41
+ alias_method :should, :test
42
+ alias_method :describe, :context
43
+ end
44
+
45
+ private
46
+
47
+ def self.setup_blocks
48
+ @setup_blocks ||= []
49
+ end
50
+
51
+ def self.context_name(name)
52
+ "Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}".to_sym
53
+ end
54
+
55
+ def self.test_name(name)
56
+ "test_#{sanitize_name(name).gsub(/\s+/,'_')}".to_sym
57
+ end
58
+
59
+ def self.sanitize_name(name)
60
+ name.gsub(/\W+/, ' ').strip
61
+ end
62
+ end
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
2
 
3
- describe "ERB Templates" do
3
+ class ERBTest < Test::Unit::TestCase
4
4
  def erb_app(&block)
5
5
  mock_app {
6
6
  set :views, File.dirname(__FILE__) + '/views'
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
2
 
3
- describe 'Registering extensions' do
3
+ class ExtensionsTest < Test::Unit::TestCase
4
4
  module FooExtensions
5
5
  def foo
6
6
  end
@@ -1,6 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
2
 
3
- describe "Filters" do
3
+ class FilterTest < Test::Unit::TestCase
4
4
  it "executes filters in the order defined" do
5
5
  count = 0
6
6
  mock_app do
@@ -1,6 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
+ require 'haml'
2
3
 
3
- describe "HAML Templates" do
4
+ class HAMLTest < Test::Unit::TestCase
4
5
  def haml_app(&block)
5
6
  mock_app {
6
7
  set :views, File.dirname(__FILE__) + '/views'
@@ -47,9 +48,12 @@ describe "HAML Templates" do
47
48
  end
48
49
 
49
50
  it "passes HAML options to the Haml engine" do
50
- haml_app {
51
- haml "!!!\n%h1 Hello World", :options => {:format => :html5}
51
+ mock_app {
52
+ get '/' do
53
+ haml "!!!\n%h1 Hello World", :format => :html5
54
+ end
52
55
  }
56
+ get '/'
53
57
  assert ok?
54
58
  assert_equal "<!DOCTYPE html>\n<h1>Hello World</h1>\n", body
55
59
  end
@@ -65,4 +69,22 @@ describe "HAML Templates" do
65
69
  assert ok?
66
70
  assert_equal "<!DOCTYPE html>\n<h1>Hello World</h1>\n", body
67
71
  end
72
+
73
+ it "merges the default HAML options with the overrides and passes them to the Haml engine" do
74
+ mock_app {
75
+ set :haml, {:format => :html5, :attr_wrapper => '"'} # default HAML attr are <tag attr='single-quoted'>
76
+ get '/' do
77
+ haml "!!!\n%h1{:class => :header} Hello World"
78
+ end
79
+ get '/html4' do
80
+ haml "!!!\n%h1{:class => 'header'} Hello World", :format => :html4
81
+ end
82
+ }
83
+ get '/'
84
+ assert ok?
85
+ assert_equal "<!DOCTYPE html>\n<h1 class=\"header\">Hello World</h1>\n", body
86
+ get '/html4'
87
+ assert ok?
88
+ assert_match(/^<!DOCTYPE html PUBLIC (.*) HTML 4.01/, body)
89
+ end
68
90
  end
@@ -5,71 +5,39 @@ rescue LoadError
5
5
  require 'rack'
6
6
  end
7
7
 
8
+ testdir = File.dirname(__FILE__)
9
+ $LOAD_PATH.unshift testdir unless $LOAD_PATH.include?(testdir)
10
+
8
11
  libdir = File.dirname(File.dirname(__FILE__)) + '/lib'
9
12
  $LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
10
13
 
11
- require 'test/unit'
14
+ require 'contest'
12
15
  require 'sinatra/test'
13
16
 
17
+ require 'haml'
18
+ require 'sass'
19
+ require 'builder'
20
+
14
21
  class Sinatra::Base
15
22
  # Allow assertions in request context
16
23
  include Test::Unit::Assertions
17
24
  end
18
25
 
26
+ Sinatra::Base.set :environment, :test
27
+
19
28
  class Test::Unit::TestCase
20
29
  include Sinatra::Test
21
30
 
31
+ class << self
32
+ alias_method :it, :test
33
+ end
34
+
22
35
  # Sets up a Sinatra::Base subclass defined with the block
23
36
  # given. Used in setup or individual spec methods to establish
24
37
  # the application.
25
38
  def mock_app(base=Sinatra::Base, &block)
26
39
  @app = Sinatra.new(base, &block)
27
40
  end
28
-
29
- def restore_default_options
30
- Sinatra::Default.set(
31
- :environment => :development,
32
- :raise_errors => Proc.new { test? },
33
- :dump_errors => true,
34
- :sessions => false,
35
- :logging => Proc.new { ! test? },
36
- :methodoverride => true,
37
- :static => true,
38
- :run => Proc.new { ! test? }
39
- )
40
- end
41
- end
42
-
43
- ##
44
- # test/spec/mini
45
- # http://pastie.caboo.se/158871
46
- # chris@ozmm.org
47
- #
48
- def describe(*args, &block)
49
- return super unless (name = args.first.capitalize) && block
50
- name = "#{name.gsub(/\W/, '')}Test"
51
- Object.send :const_set, name, Class.new(Test::Unit::TestCase)
52
- klass = Object.const_get(name)
53
- klass.class_eval do
54
- def self.it(name, &block)
55
- define_method("test_#{name.gsub(/\W/,'_').downcase}", &block)
56
- end
57
- def self.xspecify(*args) end
58
- def self.before(&block) define_method(:setup, &block) end
59
- def self.after(&block) define_method(:teardown, &block) end
60
- end
61
- klass.class_eval &block
62
- klass
63
- end
64
-
65
- def describe_option(name, &block)
66
- klass = describe("Option #{name}", &block)
67
- klass.before do
68
- restore_default_options
69
- @base = Sinatra.new
70
- @default = Class.new(Sinatra::Default)
71
- end
72
- klass
73
41
  end
74
42
 
75
43
  # Do not output warnings for the duration of the block.
@@ -1,497 +1,499 @@
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
99
- end
100
-
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
- }
151
-
152
- get '/'
153
- assert ok?
154
- assert_equal 'bar', response['X-Foo']
155
- assert_equal 'bling', response['X-Baz']
156
- assert_equal 'kthx', body
157
- end
158
-
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
- }
166
-
167
- get '/'
168
- assert ok?
169
- assert_equal 'bar', response['X-Foo']
170
- end
171
- end
172
-
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
- }
180
-
181
- get '/', :env => { 'rack.session' => { :foo => 'bar' } }
182
- assert_equal 'bar', body
183
- end
184
-
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
- }
193
-
194
- get '/'
195
- assert_equal 'Hi', body
196
- end
197
- end
198
-
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
208
-
209
- it 'returns nil when given nil' do
210
- assert media_type(nil).nil?
211
- end
212
-
213
- it 'returns nil when media type not registered' do
214
- assert media_type(:bizzle).nil?
215
- end
3
+ class HelpersTest < Test::Unit::TestCase
4
+ describe 'status' do
5
+ setup do
6
+ mock_app {
7
+ get '/' do
8
+ status 207
9
+ nil
10
+ end
11
+ }
12
+ end
216
13
 
217
- it 'returns the argument when given a media type string' do
218
- assert_equal 'text/plain', media_type('text/plain')
14
+ it 'sets the response status code' do
15
+ get '/'
16
+ assert_equal 207, response.status
17
+ end
219
18
  end
220
- end
221
19
 
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
- }
230
-
231
- get '/'
232
- assert_equal 'text/plain', response['Content-Type']
233
- assert_equal 'Hello World', body
234
- end
20
+ describe 'body' do
21
+ it 'takes a block for defered body generation' do
22
+ mock_app {
23
+ get '/' do
24
+ body { 'Hello World' }
25
+ end
26
+ }
235
27
 
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
28
+ get '/'
29
+ assert_equal 'Hello World', body
30
+ end
249
31
 
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
- }
258
-
259
- get '/foo.xml'
260
- assert ok?
261
- assert_equal 'application/foo', response['Content-Type']
262
- assert_equal 'I AM FOO', body
263
- end
32
+ it 'takes a String, Array, or other object responding to #each' do
33
+ mock_app {
34
+ get '/' do
35
+ body 'Hello World'
36
+ end
37
+ }
264
38
 
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' }
39
+ get '/'
40
+ assert_equal 'Hello World', body
41
+ end
273
42
  end
274
- end
275
43
 
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
44
+ describe 'redirect' do
45
+ it 'uses a 302 when only a path is given' do
46
+ mock_app {
47
+ get '/' do
48
+ redirect '/foo'
49
+ fail 'redirect should halt'
50
+ end
51
+ }
52
+
53
+ get '/'
54
+ assert_equal 302, status
55
+ assert_equal '', body
56
+ assert_equal '/foo', response['Location']
57
+ end
58
+
59
+ it 'uses the code given when specified' do
60
+ mock_app {
61
+ get '/' do
62
+ redirect '/foo', 301
63
+ fail 'redirect should halt'
64
+ end
65
+ }
66
+
67
+ get '/'
68
+ assert_equal 301, status
69
+ assert_equal '', body
70
+ assert_equal '/foo', response['Location']
71
+ end
72
+
73
+ it 'redirects back to request.referer when passed back' do
74
+ mock_app {
75
+ get '/try_redirect' do
76
+ redirect back
77
+ end
78
+ }
281
79
 
282
- after do
283
- File.unlink @file
284
- @file = nil
80
+ request = Rack::MockRequest.new(@app)
81
+ response = request.get('/try_redirect', 'HTTP_REFERER' => '/foo')
82
+ assert_equal 302, response.status
83
+ assert_equal '/foo', response['Location']
84
+ end
285
85
  end
286
86
 
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
87
+ describe '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
99
+ end
100
+
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
+ }
295
121
 
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
122
+ get '/'
123
+ assert_equal 500, status
124
+ assert_equal 'FAIL', body
125
+ end
301
126
  end
302
127
 
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
128
+ describe '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
+ }
308
136
 
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']
137
+ get '/'
138
+ assert_equal 404, status
139
+ assert_equal '', body
140
+ end
313
141
  end
314
142
 
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']
319
- end
143
+ describe '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
+ }
151
+
152
+ get '/'
153
+ assert ok?
154
+ assert_equal 'bar', response['X-Foo']
155
+ assert_equal 'bling', response['X-Baz']
156
+ assert_equal 'kthx', body
157
+ end
158
+
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
+ }
320
166
 
321
- it "returns a 404 when not found" do
322
- mock_app {
323
- get '/' do
324
- send_file 'this-file-does-not-exist.txt'
325
- end
326
- }
327
- get '/'
328
- assert not_found?
167
+ get '/'
168
+ assert ok?
169
+ assert_equal 'bar', response['X-Foo']
170
+ end
329
171
  end
330
172
 
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
173
+ describe 'session' do
174
+ it 'uses the existing rack.session' do
175
+ mock_app {
176
+ get '/' do
177
+ session[:foo]
178
+ end
179
+ }
180
+
181
+ get '/', :env => { 'rack.session' => { :foo => 'bar' } }
182
+ assert_equal 'bar', body
183
+ end
184
+
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
+ }
336
193
 
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']
194
+ get '/'
195
+ assert_equal 'Hi', body
196
+ end
341
197
  end
342
198
 
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
199
+ describe 'media_type' do
200
+ include Sinatra::Helpers
349
201
 
350
- describe 'Helpers#last_modified' do
351
- before do
352
- now = Time.now
353
- mock_app {
354
- get '/' do
355
- body { 'Hello World' }
356
- last_modified now
357
- 'Boo!'
358
- end
359
- }
360
- @now = now
361
- end
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
362
208
 
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
209
+ it 'returns nil when given nil' do
210
+ assert media_type(nil).nil?
211
+ end
367
212
 
368
- it 'returns a body when conditional get misses' do
369
- get '/'
370
- assert_equal 200, status
371
- assert_equal 'Boo!', body
372
- end
213
+ it 'returns nil when media type not registered' do
214
+ assert media_type(:bizzle).nil?
215
+ end
373
216
 
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
217
+ it 'returns the argument when given a media type string' do
218
+ assert_equal 'text/plain', media_type('text/plain')
219
+ end
378
220
  end
379
- end
380
221
 
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
- }
390
- end
222
+ describe '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
+ }
230
+
231
+ get '/'
232
+ assert_equal 'text/plain', response['Content-Type']
233
+ assert_equal 'Hello World', body
234
+ end
235
+
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
249
+
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
+ }
258
+
259
+ get '/foo.xml'
260
+ assert ok?
261
+ assert_equal 'application/foo', response['Content-Type']
262
+ assert_equal 'I AM FOO', body
263
+ end
264
+
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
+ }
391
272
 
392
- it 'sets the ETag header' do
393
- get '/'
394
- assert_equal '"FOO"', response['ETag']
273
+ assert_raise(RuntimeError) { get '/foo.xml' }
274
+ end
395
275
  end
396
276
 
397
- it 'returns a body when conditional get misses' do
398
- get '/'
399
- assert_equal 200, status
400
- assert_equal 'Boo!', body
401
- end
277
+ describe 'send_file' do
278
+ setup do
279
+ @file = File.dirname(__FILE__) + '/file.txt'
280
+ File.open(@file, 'wb') { |io| io.write('Hello World') }
281
+ end
402
282
 
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
283
+ def teardown
284
+ File.unlink @file
285
+ @file = nil
286
+ end
408
287
 
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
288
+ def send_file_app(opts={})
289
+ path = @file
290
+ mock_app {
291
+ get '/file.txt' do
292
+ send_file path, opts
293
+ end
294
+ }
295
+ end
296
+
297
+ it "sends the contents of the file" do
298
+ send_file_app
299
+ get '/file.txt'
300
+ assert ok?
301
+ assert_equal 'Hello World', body
302
+ end
303
+
304
+ it 'sets the Content-Type response header if a mime-type can be located' do
305
+ send_file_app
306
+ get '/file.txt'
307
+ assert_equal 'text/plain', response['Content-Type']
308
+ end
309
+
310
+ it 'sets the Content-Length response header' do
311
+ send_file_app
312
+ get '/file.txt'
313
+ assert_equal 'Hello World'.length.to_s, response['Content-Length']
314
+ end
315
+
316
+ it 'sets the Last-Modified response header' do
317
+ send_file_app
318
+ get '/file.txt'
319
+ assert_equal File.mtime(@file).httpdate, response['Last-Modified']
320
+ end
321
+
322
+ it "returns a 404 when not found" do
323
+ mock_app {
324
+ get '/' do
325
+ send_file 'this-file-does-not-exist.txt'
326
+ end
327
+ }
328
+ get '/'
329
+ assert not_found?
330
+ end
331
+
332
+ it "does not set the Content-Disposition header by default" do
333
+ send_file_app
334
+ get '/file.txt'
335
+ assert_nil response['Content-Disposition']
336
+ end
337
+
338
+ it "sets the Content-Disposition header when :disposition set to 'attachment'" do
339
+ send_file_app :disposition => 'attachment'
340
+ get '/file.txt'
341
+ assert_equal 'attachment; filename="file.txt"', response['Content-Disposition']
342
+ end
343
+
344
+ it "sets the Content-Disposition header when :filename provided" do
345
+ send_file_app :filename => 'foo.txt'
346
+ get '/file.txt'
347
+ assert_equal 'attachment; filename="foo.txt"', response['Content-Disposition']
348
+ end
349
+ end
350
+
351
+ describe 'last_modified' do
352
+ setup do
353
+ now = Time.now
354
+ mock_app {
355
+ get '/' do
356
+ body { 'Hello World' }
357
+ last_modified now
358
+ 'Boo!'
359
+ end
360
+ }
361
+ @now = now
362
+ end
363
+
364
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
365
+ get '/'
366
+ assert_equal @now.httpdate, response['Last-Modified']
367
+ end
368
+
369
+ it 'returns a body when conditional get misses' do
370
+ get '/'
371
+ assert_equal 200, status
372
+ assert_equal 'Boo!', body
373
+ end
374
+
375
+ it 'halts when a conditional GET matches' do
376
+ get '/', :env => { 'HTTP_IF_MODIFIED_SINCE' => @now.httpdate }
377
+ assert_equal 304, status
378
+ assert_equal '', body
379
+ end
380
+ end
381
+
382
+ describe 'etag' do
383
+ setup do
384
+ mock_app {
385
+ get '/' do
386
+ body { 'Hello World' }
387
+ etag 'FOO'
388
+ 'Boo!'
389
+ end
390
+ }
391
+ end
392
+
393
+ it 'sets the ETag header' do
394
+ get '/'
395
+ assert_equal '"FOO"', response['ETag']
396
+ end
397
+
398
+ it 'returns a body when conditional get misses' do
399
+ get '/'
400
+ assert_equal 200, status
401
+ assert_equal 'Boo!', body
402
+ end
403
+
404
+ it 'halts when a conditional GET matches' do
405
+ get '/', :env => { 'HTTP_IF_NONE_MATCH' => '"FOO"' }
406
+ assert_equal 304, status
407
+ assert_equal '', body
408
+ end
409
+
410
+ it 'should handle multiple ETag values in If-None-Match header' do
411
+ get '/', :env => { 'HTTP_IF_NONE_MATCH' => '"BAR", *' }
412
+ assert_equal 304, status
413
+ assert_equal '', body
414
+ end
415
+
416
+ it 'uses a weak etag with the :weak option' do
417
+ mock_app {
418
+ get '/' do
419
+ etag 'FOO', :weak
420
+ "that's weak, dude."
421
+ end
422
+ }
423
+ get '/'
424
+ assert_equal 'W/"FOO"', response['ETag']
425
+ end
413
426
  end
414
427
 
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']
424
- end
425
- end
428
+ describe 'back' do
429
+ it "makes redirecting back pretty" do
430
+ mock_app {
431
+ get '/foo' do
432
+ redirect back
433
+ end
434
+ }
426
435
 
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
- }
434
-
435
- get '/foo', {}, 'HTTP_REFERER' => 'http://github.com'
436
- assert redirect?
437
- assert_equal "http://github.com", response.location
436
+ get '/foo', {}, 'HTTP_REFERER' => 'http://github.com'
437
+ assert redirect?
438
+ assert_equal "http://github.com", response.location
439
+ end
438
440
  end
439
- end
440
441
 
441
- module HelperOne; def one; '1'; end; end
442
- module HelperTwo; def two; '2'; end; end
442
+ module ::HelperOne; def one; '1'; end; end
443
+ module ::HelperTwo; def two; '2'; end; end
443
444
 
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
445
+ describe 'Adding new helpers' do
446
+ it 'takes a list of modules to mix into the app' do
447
+ mock_app {
448
+ helpers ::HelperOne, ::HelperTwo
448
449
 
449
- get '/one' do
450
- one
451
- end
450
+ get '/one' do
451
+ one
452
+ end
452
453
 
453
- get '/two' do
454
- two
455
- end
456
- }
454
+ get '/two' do
455
+ two
456
+ end
457
+ }
457
458
 
458
- get '/one'
459
- assert_equal '1', body
459
+ get '/one'
460
+ assert_equal '1', body
460
461
 
461
- get '/two'
462
- assert_equal '2', body
463
- end
462
+ get '/two'
463
+ assert_equal '2', body
464
+ end
464
465
 
465
- it 'takes a block to mix into the app' do
466
- mock_app {
467
- helpers do
468
- def foo
469
- 'foo'
466
+ it 'takes a block to mix into the app' do
467
+ mock_app {
468
+ helpers do
469
+ def foo
470
+ 'foo'
471
+ end
470
472
  end
471
- end
472
473
 
473
- get '/' do
474
- foo
475
- end
476
- }
474
+ get '/' do
475
+ foo
476
+ end
477
+ }
477
478
 
478
- get '/'
479
- assert_equal 'foo', body
480
- end
479
+ get '/'
480
+ assert_equal 'foo', body
481
+ end
481
482
 
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
483
+ it 'evaluates the block in class context so that methods can be aliased' do
484
+ mock_app {
485
+ helpers do
486
+ alias_method :h, :escape_html
487
+ end
487
488
 
488
- get '/' do
489
- h('42 < 43')
490
- end
491
- }
489
+ get '/' do
490
+ h('42 < 43')
491
+ end
492
+ }
492
493
 
493
- get '/'
494
- assert ok?
495
- assert_equal '42 &lt; 43', body
494
+ get '/'
495
+ assert ok?
496
+ assert_equal '42 &lt; 43', body
497
+ end
496
498
  end
497
499
  end