sinatra 0.9.1.1 → 0.9.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.

Potentially problematic release.


This version of sinatra might be problematic. Click here for more details.

@@ -1,6 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
+ require 'builder'
2
3
 
3
- describe "Builder Templates" do
4
+ class BuilderTest < Test::Unit::TestCase
4
5
  def builder_app(&block)
5
6
  mock_app {
6
7
  set :views, File.dirname(__FILE__) + '/views'
@@ -0,0 +1,64 @@
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
+ unless method_defined?(:empty?)
10
+ def empty?
11
+ false
12
+ end
13
+ end
14
+ end
15
+
16
+ # We added setup, test and context as class methods, and the instance
17
+ # method setup now iterates on the setup blocks. Note that all setup
18
+ # blocks must be defined with the block syntax. Adding a setup instance
19
+ # method defeats the purpose of this library.
20
+ class Test::Unit::TestCase
21
+ def self.setup(&block)
22
+ setup_blocks << block
23
+ end
24
+
25
+ def setup
26
+ self.class.setup_blocks.each do |block|
27
+ instance_eval(&block)
28
+ end
29
+ end
30
+
31
+ def self.context(name, &block)
32
+ subclass = Class.new(self.superclass)
33
+ subclass.setup_blocks.unshift(*setup_blocks)
34
+ subclass.class_eval(&block)
35
+ const_set(context_name(name), subclass)
36
+ end
37
+
38
+ def self.test(name, &block)
39
+ define_method(test_name(name), &block)
40
+ end
41
+
42
+ class << self
43
+ alias_method :should, :test
44
+ alias_method :describe, :context
45
+ end
46
+
47
+ private
48
+
49
+ def self.setup_blocks
50
+ @setup_blocks ||= []
51
+ end
52
+
53
+ def self.context_name(name)
54
+ "Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}".to_sym
55
+ end
56
+
57
+ def self.test_name(name)
58
+ "test_#{sanitize_name(name).gsub(/\s+/,'_')}".to_sym
59
+ end
60
+
61
+ def self.sanitize_name(name)
62
+ name.gsub(/\W+/, ' ').strip
63
+ end
64
+ 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
@@ -25,6 +25,12 @@ describe 'Registering extensions' do
25
25
  end
26
26
  end
27
27
 
28
+ module PainExtensions
29
+ def foo=(name); end
30
+ def bar?(name); end
31
+ def fizz!(name); end
32
+ end
33
+
28
34
  it 'will add the methods to the DSL for the class in which you register them and its subclasses' do
29
35
  Sinatra::Base.register FooExtensions
30
36
  assert Sinatra::Base.respond_to?(:foo)
@@ -50,6 +56,16 @@ describe 'Registering extensions' do
50
56
  map { |m| m.to_sym }.include?(:im_hiding_in_ur_foos)
51
57
  end
52
58
 
59
+ it 'will handle special method names' do
60
+ Sinatra::Default.register PainExtensions
61
+ assert Sinatra::Delegator.private_instance_methods.
62
+ map { |m| m.to_sym }.include?(:foo=)
63
+ assert Sinatra::Delegator.private_instance_methods.
64
+ map { |m| m.to_sym }.include?(:bar?)
65
+ assert Sinatra::Delegator.private_instance_methods.
66
+ map { |m| m.to_sym }.include?(:fizz!)
67
+ end
68
+
53
69
  it 'will not delegate methods on Base#register' do
54
70
  Sinatra::Base.register QuuxExtensions
55
71
  assert !Sinatra::Delegator.private_instance_methods.include?("quux")
@@ -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
@@ -1,3 +1,5 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
1
3
  begin
2
4
  require 'rack'
3
5
  rescue LoadError
@@ -5,19 +7,35 @@ rescue LoadError
5
7
  require 'rack'
6
8
  end
7
9
 
10
+ testdir = File.dirname(__FILE__)
11
+ $LOAD_PATH.unshift testdir unless $LOAD_PATH.include?(testdir)
12
+
8
13
  libdir = File.dirname(File.dirname(__FILE__)) + '/lib'
9
14
  $LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
10
15
 
11
- require 'test/unit'
12
- require 'sinatra/test'
16
+ require 'contest'
17
+ require 'rack/test'
18
+ require 'sinatra/base'
13
19
 
14
20
  class Sinatra::Base
15
21
  # Allow assertions in request context
16
22
  include Test::Unit::Assertions
17
23
  end
18
24
 
25
+ Sinatra::Base.set :environment, :test
26
+
19
27
  class Test::Unit::TestCase
20
- include Sinatra::Test
28
+ include Rack::Test::Methods
29
+
30
+ class << self
31
+ alias_method :it, :test
32
+ end
33
+
34
+ alias_method :response, :last_response
35
+
36
+ setup do
37
+ Sinatra::Base.set :environment, :test
38
+ end
21
39
 
22
40
  # Sets up a Sinatra::Base subclass defined with the block
23
41
  # given. Used in setup or individual spec methods to establish
@@ -26,56 +44,33 @@ class Test::Unit::TestCase
26
44
  @app = Sinatra.new(base, &block)
27
45
  end
28
46
 
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
- )
47
+ def app
48
+ Rack::Lint.new(@app)
49
+ end
50
+
51
+ def body
52
+ response.body.to_s
40
53
  end
41
- end
42
54
 
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)
55
+ # Delegate other missing methods to response.
56
+ def method_missing(name, *args, &block)
57
+ if response && response.respond_to?(name)
58
+ response.send(name, *args, &block)
59
+ else
60
+ super
56
61
  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
62
  end
61
- klass.class_eval &block
62
- klass
63
- end
64
63
 
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)
64
+ # Also check response since we delegate there.
65
+ def respond_to?(symbol, include_private=false)
66
+ super || (response && response.respond_to?(symbol, include_private))
71
67
  end
72
- klass
73
- end
74
68
 
75
- # Do not output warnings for the duration of the block.
76
- def silence_warnings
77
- $VERBOSE, v = nil, $VERBOSE
78
- yield
79
- ensure
80
- $VERBOSE = v
69
+ # Do not output warnings for the duration of the block.
70
+ def silence_warnings
71
+ $VERBOSE, v = nil, $VERBOSE
72
+ yield
73
+ ensure
74
+ $VERBOSE = v
75
+ end
81
76
  end
@@ -1,497 +1,503 @@
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
- }
3
+ class HelpersTest < Test::Unit::TestCase
4
+ def test_default
5
+ assert true
11
6
  end
12
7
 
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
8
+ describe 'status' do
9
+ setup do
10
+ mock_app {
11
+ get '/' do
12
+ status 207
13
+ nil
14
+ end
15
+ }
16
+ end
216
17
 
217
- it 'returns the argument when given a media type string' do
218
- assert_equal 'text/plain', media_type('text/plain')
18
+ it 'sets the response status code' do
19
+ get '/'
20
+ assert_equal 207, response.status
21
+ end
219
22
  end
220
- end
221
23
 
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
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
+ }
235
31
 
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
32
+ get '/'
33
+ assert_equal 'Hello World', body
34
+ end
249
35
 
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
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
+ }
264
42
 
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' }
43
+ get '/'
44
+ assert_equal 'Hello World', body
45
+ end
273
46
  end
274
- end
275
47
 
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
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
+ }
281
83
 
282
- after do
283
- File.unlink @file
284
- @file = nil
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
285
89
  end
286
90
 
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
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
+ }
295
125
 
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
126
+ get '/'
127
+ assert_equal 500, status
128
+ assert_equal 'FAIL', body
129
+ end
301
130
  end
302
131
 
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
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
+ }
308
140
 
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']
141
+ get '/'
142
+ assert_equal 404, status
143
+ assert_equal '', body
144
+ end
313
145
  end
314
146
 
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
147
+ describe 'headers' do
148
+ it 'sets headers on the response object when given a Hash' do
149
+ mock_app {
150
+ get '/' do
151
+ headers 'X-Foo' => 'bar', 'X-Baz' => 'bling'
152
+ 'kthx'
153
+ end
154
+ }
155
+
156
+ get '/'
157
+ assert ok?
158
+ assert_equal 'bar', response['X-Foo']
159
+ assert_equal 'bling', response['X-Baz']
160
+ assert_equal 'kthx', body
161
+ end
162
+
163
+ it 'returns the response headers hash when no hash provided' do
164
+ mock_app {
165
+ get '/' do
166
+ headers['X-Foo'] = 'bar'
167
+ 'kthx'
168
+ end
169
+ }
320
170
 
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?
171
+ get '/'
172
+ assert ok?
173
+ assert_equal 'bar', response['X-Foo']
174
+ end
329
175
  end
330
176
 
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
177
+ describe 'session' do
178
+ it 'uses the existing rack.session' do
179
+ mock_app {
180
+ get '/' do
181
+ session[:foo]
182
+ end
183
+ }
184
+
185
+ get '/', {}, { 'rack.session' => { :foo => 'bar' } }
186
+ assert_equal 'bar', body
187
+ end
188
+
189
+ it 'creates a new session when none provided' do
190
+ mock_app {
191
+ get '/' do
192
+ assert session.empty?
193
+ session[:foo] = 'bar'
194
+ 'Hi'
195
+ end
196
+ }
336
197
 
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']
198
+ get '/'
199
+ assert_equal 'Hi', body
200
+ end
341
201
  end
342
202
 
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
203
+ describe 'media_type' do
204
+ include Sinatra::Helpers
349
205
 
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
206
+ it "looks up media types in Rack's MIME registry" do
207
+ Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
208
+ assert_equal 'application/foo', media_type('foo')
209
+ assert_equal 'application/foo', media_type('.foo')
210
+ assert_equal 'application/foo', media_type(:foo)
211
+ end
362
212
 
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
213
+ it 'returns nil when given nil' do
214
+ assert media_type(nil).nil?
215
+ end
367
216
 
368
- it 'returns a body when conditional get misses' do
369
- get '/'
370
- assert_equal 200, status
371
- assert_equal 'Boo!', body
372
- end
217
+ it 'returns nil when media type not registered' do
218
+ assert media_type(:bizzle).nil?
219
+ end
373
220
 
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
221
+ it 'returns the argument when given a media type string' do
222
+ assert_equal 'text/plain', media_type('text/plain')
223
+ end
378
224
  end
379
- end
380
225
 
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
226
+ describe 'content_type' do
227
+ it 'sets the Content-Type header' do
228
+ mock_app {
229
+ get '/' do
230
+ content_type 'text/plain'
231
+ 'Hello World'
232
+ end
233
+ }
234
+
235
+ get '/'
236
+ assert_equal 'text/plain', response['Content-Type']
237
+ assert_equal 'Hello World', body
238
+ end
239
+
240
+ it 'takes media type parameters (like charset=)' do
241
+ mock_app {
242
+ get '/' do
243
+ content_type 'text/html', :charset => 'utf-8'
244
+ "<h1>Hello, World</h1>"
245
+ end
246
+ }
247
+
248
+ get '/'
249
+ assert ok?
250
+ assert_equal 'text/html;charset=utf-8', response['Content-Type']
251
+ assert_equal "<h1>Hello, World</h1>", body
252
+ end
253
+
254
+ it "looks up symbols in Rack's mime types dictionary" do
255
+ Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
256
+ mock_app {
257
+ get '/foo.xml' do
258
+ content_type :foo
259
+ "I AM FOO"
260
+ end
261
+ }
262
+
263
+ get '/foo.xml'
264
+ assert ok?
265
+ assert_equal 'application/foo', response['Content-Type']
266
+ assert_equal 'I AM FOO', body
267
+ end
268
+
269
+ it 'fails when no mime type is registered for the argument provided' do
270
+ mock_app {
271
+ get '/foo.xml' do
272
+ content_type :bizzle
273
+ "I AM FOO"
274
+ end
275
+ }
391
276
 
392
- it 'sets the ETag header' do
393
- get '/'
394
- assert_equal '"FOO"', response['ETag']
277
+ assert_raise(RuntimeError) { get '/foo.xml' }
278
+ end
395
279
  end
396
280
 
397
- it 'returns a body when conditional get misses' do
398
- get '/'
399
- assert_equal 200, status
400
- assert_equal 'Boo!', body
401
- end
281
+ describe 'send_file' do
282
+ setup do
283
+ @file = File.dirname(__FILE__) + '/file.txt'
284
+ File.open(@file, 'wb') { |io| io.write('Hello World') }
285
+ end
402
286
 
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
287
+ def teardown
288
+ File.unlink @file
289
+ @file = nil
290
+ end
408
291
 
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
292
+ def send_file_app(opts={})
293
+ path = @file
294
+ mock_app {
295
+ get '/file.txt' do
296
+ send_file path, opts
297
+ end
298
+ }
299
+ end
300
+
301
+ it "sends the contents of the file" do
302
+ send_file_app
303
+ get '/file.txt'
304
+ assert ok?
305
+ assert_equal 'Hello World', body
306
+ end
307
+
308
+ it 'sets the Content-Type response header if a mime-type can be located' do
309
+ send_file_app
310
+ get '/file.txt'
311
+ assert_equal 'text/plain', response['Content-Type']
312
+ end
313
+
314
+ it 'sets the Content-Length response header' do
315
+ send_file_app
316
+ get '/file.txt'
317
+ assert_equal 'Hello World'.length.to_s, response['Content-Length']
318
+ end
319
+
320
+ it 'sets the Last-Modified response header' do
321
+ send_file_app
322
+ get '/file.txt'
323
+ assert_equal File.mtime(@file).httpdate, response['Last-Modified']
324
+ end
325
+
326
+ it "returns a 404 when not found" do
327
+ mock_app {
328
+ get '/' do
329
+ send_file 'this-file-does-not-exist.txt'
330
+ end
331
+ }
332
+ get '/'
333
+ assert not_found?
334
+ end
335
+
336
+ it "does not set the Content-Disposition header by default" do
337
+ send_file_app
338
+ get '/file.txt'
339
+ assert_nil response['Content-Disposition']
340
+ end
341
+
342
+ it "sets the Content-Disposition header when :disposition set to 'attachment'" do
343
+ send_file_app :disposition => 'attachment'
344
+ get '/file.txt'
345
+ assert_equal 'attachment; filename="file.txt"', response['Content-Disposition']
346
+ end
347
+
348
+ it "sets the Content-Disposition header when :filename provided" do
349
+ send_file_app :filename => 'foo.txt'
350
+ get '/file.txt'
351
+ assert_equal 'attachment; filename="foo.txt"', response['Content-Disposition']
352
+ end
353
+ end
354
+
355
+ describe 'last_modified' do
356
+ setup do
357
+ now = Time.now
358
+ mock_app {
359
+ get '/' do
360
+ body { 'Hello World' }
361
+ last_modified now
362
+ 'Boo!'
363
+ end
364
+ }
365
+ @now = now
366
+ end
367
+
368
+ it 'sets the Last-Modified header to a valid RFC 2616 date value' do
369
+ get '/'
370
+ assert_equal @now.httpdate, response['Last-Modified']
371
+ end
372
+
373
+ it 'returns a body when conditional get misses' do
374
+ get '/'
375
+ assert_equal 200, status
376
+ assert_equal 'Boo!', body
377
+ end
378
+
379
+ it 'halts when a conditional GET matches' do
380
+ get '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @now.httpdate }
381
+ assert_equal 304, status
382
+ assert_equal '', body
383
+ end
384
+ end
385
+
386
+ describe 'etag' do
387
+ setup do
388
+ mock_app {
389
+ get '/' do
390
+ body { 'Hello World' }
391
+ etag 'FOO'
392
+ 'Boo!'
393
+ end
394
+ }
395
+ end
396
+
397
+ it 'sets the ETag header' do
398
+ get '/'
399
+ assert_equal '"FOO"', response['ETag']
400
+ end
401
+
402
+ it 'returns a body when conditional get misses' do
403
+ get '/'
404
+ assert_equal 200, status
405
+ assert_equal 'Boo!', body
406
+ end
407
+
408
+ it 'halts when a conditional GET matches' do
409
+ get '/', {}, { 'HTTP_IF_NONE_MATCH' => '"FOO"' }
410
+ assert_equal 304, status
411
+ assert_equal '', body
412
+ end
413
+
414
+ it 'should handle multiple ETag values in If-None-Match header' do
415
+ get '/', {}, { 'HTTP_IF_NONE_MATCH' => '"BAR", *' }
416
+ assert_equal 304, status
417
+ assert_equal '', body
418
+ end
419
+
420
+ it 'uses a weak etag with the :weak option' do
421
+ mock_app {
422
+ get '/' do
423
+ etag 'FOO', :weak
424
+ "that's weak, dude."
425
+ end
426
+ }
427
+ get '/'
428
+ assert_equal 'W/"FOO"', response['ETag']
429
+ end
413
430
  end
414
431
 
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
432
+ describe 'back' do
433
+ it "makes redirecting back pretty" do
434
+ mock_app {
435
+ get '/foo' do
436
+ redirect back
437
+ end
438
+ }
426
439
 
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
440
+ get '/foo', {}, 'HTTP_REFERER' => 'http://github.com'
441
+ assert redirect?
442
+ assert_equal "http://github.com", response.location
443
+ end
438
444
  end
439
- end
440
445
 
441
- module HelperOne; def one; '1'; end; end
442
- module HelperTwo; def two; '2'; end; end
446
+ module ::HelperOne; def one; '1'; end; end
447
+ module ::HelperTwo; def two; '2'; end; end
443
448
 
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
449
+ describe 'Adding new helpers' do
450
+ it 'takes a list of modules to mix into the app' do
451
+ mock_app {
452
+ helpers ::HelperOne, ::HelperTwo
448
453
 
449
- get '/one' do
450
- one
451
- end
454
+ get '/one' do
455
+ one
456
+ end
452
457
 
453
- get '/two' do
454
- two
455
- end
456
- }
458
+ get '/two' do
459
+ two
460
+ end
461
+ }
457
462
 
458
- get '/one'
459
- assert_equal '1', body
463
+ get '/one'
464
+ assert_equal '1', body
460
465
 
461
- get '/two'
462
- assert_equal '2', body
463
- end
466
+ get '/two'
467
+ assert_equal '2', body
468
+ end
464
469
 
465
- it 'takes a block to mix into the app' do
466
- mock_app {
467
- helpers do
468
- def foo
469
- 'foo'
470
+ it 'takes a block to mix into the app' do
471
+ mock_app {
472
+ helpers do
473
+ def foo
474
+ 'foo'
475
+ end
470
476
  end
471
- end
472
477
 
473
- get '/' do
474
- foo
475
- end
476
- }
478
+ get '/' do
479
+ foo
480
+ end
481
+ }
477
482
 
478
- get '/'
479
- assert_equal 'foo', body
480
- end
483
+ get '/'
484
+ assert_equal 'foo', body
485
+ end
481
486
 
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
487
+ it 'evaluates the block in class context so that methods can be aliased' do
488
+ mock_app {
489
+ helpers do
490
+ alias_method :h, :escape_html
491
+ end
487
492
 
488
- get '/' do
489
- h('42 < 43')
490
- end
491
- }
493
+ get '/' do
494
+ h('42 < 43')
495
+ end
496
+ }
492
497
 
493
- get '/'
494
- assert ok?
495
- assert_equal '42 &lt; 43', body
498
+ get '/'
499
+ assert ok?
500
+ assert_equal '42 &lt; 43', body
501
+ end
496
502
  end
497
503
  end