sinatra 0.3.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- data/AUTHORS +40 -0
- data/CHANGES +189 -0
- data/README.rdoc +146 -117
- data/Rakefile +33 -10
- data/{test → compat}/app_test.rb +11 -10
- data/{test → compat}/application_test.rb +10 -5
- data/compat/builder_test.rb +101 -0
- data/{test → compat}/custom_error_test.rb +0 -0
- data/compat/erb_test.rb +136 -0
- data/{test → compat}/events_test.rb +16 -3
- data/compat/filter_test.rb +30 -0
- data/compat/haml_test.rb +233 -0
- data/compat/helper.rb +30 -0
- data/compat/mapped_error_test.rb +72 -0
- data/{test → compat}/pipeline_test.rb +9 -4
- data/{test → compat}/public/foo.xml +0 -0
- data/compat/sass_test.rb +57 -0
- data/{test → compat}/sessions_test.rb +0 -0
- data/{test → compat}/streaming_test.rb +4 -1
- data/{test → compat}/sym_params_test.rb +0 -0
- data/{test → compat}/template_test.rb +0 -0
- data/{test → compat}/use_in_file_templates_test.rb +0 -0
- data/{test → compat}/views/foo.builder +0 -0
- data/{test → compat}/views/foo.erb +0 -0
- data/{test → compat}/views/foo.haml +0 -0
- data/{test → compat}/views/foo.sass +0 -0
- data/{test → compat}/views/foo_layout.erb +0 -0
- data/{test → compat}/views/foo_layout.haml +0 -0
- data/{test → compat}/views/layout_test/foo.builder +0 -0
- data/{test → compat}/views/layout_test/foo.erb +0 -0
- data/{test → compat}/views/layout_test/foo.haml +0 -0
- data/{test → compat}/views/layout_test/foo.sass +0 -0
- data/{test → compat}/views/layout_test/layout.builder +0 -0
- data/{test → compat}/views/layout_test/layout.erb +0 -0
- data/{test → compat}/views/layout_test/layout.haml +0 -0
- data/{test → compat}/views/layout_test/layout.sass +0 -0
- data/{test → compat}/views/no_layout/no_layout.builder +0 -0
- data/{test → compat}/views/no_layout/no_layout.haml +0 -0
- data/lib/sinatra.rb +6 -1484
- data/lib/sinatra/base.rb +838 -0
- data/lib/sinatra/compat.rb +239 -0
- data/{images → lib/sinatra/images}/404.png +0 -0
- data/{images → lib/sinatra/images}/500.png +0 -0
- data/lib/sinatra/main.rb +48 -0
- data/lib/sinatra/test.rb +114 -0
- data/lib/sinatra/test/bacon.rb +17 -0
- data/lib/sinatra/test/rspec.rb +7 -8
- data/lib/sinatra/test/spec.rb +3 -4
- data/lib/sinatra/test/unit.rb +3 -5
- data/sinatra.gemspec +68 -35
- data/test/base_test.rb +68 -0
- data/test/builder_test.rb +50 -87
- data/test/data/reload_app_file.rb +3 -0
- data/test/erb_test.rb +38 -124
- data/test/filter_test.rb +27 -22
- data/test/haml_test.rb +51 -216
- data/test/helper.rb +22 -6
- data/test/helpers_test.rb +361 -0
- data/test/mapped_error_test.rb +137 -49
- data/test/middleware_test.rb +58 -0
- data/test/options_test.rb +97 -0
- data/test/reload_test.rb +61 -0
- data/test/request_test.rb +18 -0
- data/test/result_test.rb +88 -0
- data/test/routing_test.rb +391 -0
- data/test/sass_test.rb +27 -48
- data/test/sinatra_test.rb +13 -0
- data/test/static_test.rb +57 -0
- data/test/templates_test.rb +88 -0
- data/test/views/hello.builder +1 -0
- data/test/views/hello.erb +1 -0
- data/test/views/hello.haml +1 -0
- data/test/views/hello.sass +2 -0
- data/test/views/hello.test +1 -0
- data/test/views/layout2.builder +3 -0
- data/test/views/layout2.erb +2 -0
- data/test/views/layout2.haml +2 -0
- data/test/views/layout2.test +1 -0
- metadata +80 -48
- data/ChangeLog +0 -96
- data/lib/sinatra/test/methods.rb +0 -76
- data/test/event_context_test.rb +0 -15
data/test/filter_test.rb
CHANGED
@@ -1,30 +1,35 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
2
2
|
|
3
|
-
|
3
|
+
describe "Filters" do
|
4
|
+
it "executes filters in the order defined" do
|
5
|
+
count = 0
|
6
|
+
mock_app do
|
7
|
+
get('/') { 'Hello World' }
|
8
|
+
before {
|
9
|
+
assert_equal 0, count
|
10
|
+
count = 1
|
11
|
+
}
|
12
|
+
before {
|
13
|
+
assert_equal 1, count
|
14
|
+
count = 2
|
15
|
+
}
|
16
|
+
end
|
4
17
|
|
5
|
-
|
6
|
-
|
7
|
-
|
18
|
+
get '/'
|
19
|
+
assert ok?
|
20
|
+
assert_equal 2, count
|
21
|
+
assert_equal 'Hello World', body
|
8
22
|
end
|
9
23
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
should.be.ok
|
17
|
-
body.should.be == 'Hello World'
|
18
|
-
invoked.should.be == 0x03
|
19
|
-
end
|
24
|
+
it "allows filters to modify the request" do
|
25
|
+
mock_app {
|
26
|
+
get('/foo') { 'foo' }
|
27
|
+
get('/bar') { 'bar' }
|
28
|
+
before { request.path_info = '/bar' }
|
29
|
+
}
|
20
30
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@app.before { request.path_info = '/bar' }
|
25
|
-
get_it '/foo'
|
26
|
-
should.be.ok
|
27
|
-
body.should.be == 'bar'
|
31
|
+
get '/foo'
|
32
|
+
assert ok?
|
33
|
+
assert_equal 'bar', body
|
28
34
|
end
|
29
|
-
|
30
35
|
end
|
data/test/haml_test.rb
CHANGED
@@ -1,233 +1,68 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
describe "HAML Templates" do
|
4
|
+
def haml_app(&block)
|
5
|
+
mock_app {
|
6
|
+
set :views, File.dirname(__FILE__) + '/views'
|
7
|
+
get '/', &block
|
8
|
+
}
|
9
|
+
get '/'
|
7
10
|
end
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
specify "should render" do
|
16
|
-
|
17
|
-
get '/no_layout' do
|
18
|
-
haml '== #{1+1}'
|
19
|
-
end
|
20
|
-
|
21
|
-
get_it '/no_layout'
|
22
|
-
should.be.ok
|
23
|
-
body.should == "2\n"
|
24
|
-
|
25
|
-
end
|
12
|
+
it 'renders inline HAML strings' do
|
13
|
+
haml_app { haml '%h1 Hiya' }
|
14
|
+
assert ok?
|
15
|
+
assert_equal "<h1>Hiya</h1>\n", body
|
26
16
|
end
|
27
17
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
specify "can be inline" do
|
35
|
-
|
36
|
-
layout do
|
37
|
-
'== This is #{yield}!'
|
38
|
-
end
|
39
|
-
|
40
|
-
get '/lay' do
|
41
|
-
haml 'Blake'
|
42
|
-
end
|
43
|
-
|
44
|
-
get_it '/lay'
|
45
|
-
should.be.ok
|
46
|
-
body.should.equal "This is Blake\n!\n"
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
specify "can use named layouts" do
|
51
|
-
|
52
|
-
layout :pretty do
|
53
|
-
'%h1== #{yield}'
|
54
|
-
end
|
55
|
-
|
56
|
-
get '/pretty' do
|
57
|
-
haml 'Foo', :layout => :pretty
|
58
|
-
end
|
59
|
-
|
60
|
-
get '/not_pretty' do
|
61
|
-
haml 'Bar'
|
62
|
-
end
|
63
|
-
|
64
|
-
get_it '/pretty'
|
65
|
-
body.should.equal "<h1>Foo</h1>\n"
|
66
|
-
|
67
|
-
get_it '/not_pretty'
|
68
|
-
body.should.equal "Bar\n"
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
specify "can be read from a file if they're not inlined" do
|
73
|
-
|
74
|
-
get '/foo' do
|
75
|
-
@title = 'Welcome to the Hello Program'
|
76
|
-
haml 'Blake', :layout => :foo_layout,
|
77
|
-
:views_directory => File.dirname(__FILE__) + "/views"
|
78
|
-
end
|
79
|
-
|
80
|
-
get_it '/foo'
|
81
|
-
body.should.equal "Welcome to the Hello Program\nHi Blake\n"
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
specify "can be read from file and layout from text" do
|
86
|
-
get '/foo' do
|
87
|
-
haml 'Test', :layout => '== Foo #{yield}'
|
88
|
-
end
|
89
|
-
|
90
|
-
get_it '/foo'
|
91
|
-
|
92
|
-
body.should.equal "Foo Test\n"
|
93
|
-
end
|
94
|
-
|
18
|
+
it 'renders .haml files in views path' do
|
19
|
+
haml_app { haml :hello }
|
20
|
+
assert ok?
|
21
|
+
assert_equal "<h1>Hello From Haml</h1>\n", body
|
95
22
|
end
|
96
23
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
get '/from_file' do
|
106
|
-
@name = 'Alena'
|
107
|
-
haml :foo, :views_directory => File.dirname(__FILE__) + "/views"
|
108
|
-
end
|
109
|
-
|
110
|
-
get_it '/from_file'
|
111
|
-
|
112
|
-
body.should.equal "You rock Alena!\n"
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
specify "use layout.ext by default if available" do
|
117
|
-
|
118
|
-
get '/' do
|
119
|
-
haml :foo, :views_directory => File.dirname(__FILE__) + "/views/layout_test"
|
120
|
-
end
|
121
|
-
|
122
|
-
get_it '/'
|
123
|
-
should.be.ok
|
124
|
-
body.should.equal "x This is foo!\n x\n"
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
specify "renders without layout" do
|
129
|
-
|
130
|
-
get '/' do
|
131
|
-
haml :no_layout, :views_directory => File.dirname(__FILE__) + "/views/no_layout"
|
132
|
-
end
|
133
|
-
|
134
|
-
get_it '/'
|
135
|
-
should.be.ok
|
136
|
-
body.should.equal "<h1>No Layout!</h1>\n"
|
137
|
-
|
138
|
-
end
|
139
|
-
|
140
|
-
specify "can render with no layout" do
|
141
|
-
layout do
|
142
|
-
"X\n= yield\nX"
|
143
|
-
end
|
144
|
-
|
145
|
-
get '/' do
|
146
|
-
haml 'blake', :layout => false
|
147
|
-
end
|
148
|
-
|
149
|
-
get_it '/'
|
150
|
-
|
151
|
-
body.should.equal "blake\n"
|
152
|
-
end
|
153
|
-
|
154
|
-
specify "raises error if template not found" do
|
155
|
-
get '/' do
|
156
|
-
haml :not_found
|
157
|
-
end
|
158
|
-
|
159
|
-
lambda { get_it '/' }.should.raise(Errno::ENOENT)
|
160
|
-
end
|
161
|
-
|
162
|
-
specify "use layout.ext by default if available" do
|
163
|
-
|
164
|
-
template :foo do
|
165
|
-
'asdf'
|
166
|
-
end
|
167
|
-
|
168
|
-
get '/' do
|
169
|
-
haml :foo, :layout => false,
|
170
|
-
:views_directory => File.dirname(__FILE__) + "/views/layout_test"
|
171
|
-
end
|
172
|
-
|
173
|
-
get_it '/'
|
174
|
-
should.be.ok
|
175
|
-
body.should.equal "asdf\n"
|
176
|
-
|
177
|
-
end
|
178
|
-
|
24
|
+
it "renders with inline layouts" do
|
25
|
+
mock_app {
|
26
|
+
layout { %q(%h1= 'THIS. IS. ' + yield.upcase) }
|
27
|
+
get('/') { haml '%em Sparta' }
|
28
|
+
}
|
29
|
+
get '/'
|
30
|
+
assert ok?
|
31
|
+
assert_equal "<h1>THIS. IS. <EM>SPARTA</EM></h1>\n", body
|
179
32
|
end
|
180
33
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
get '/' do
|
189
|
-
haml 'foo'
|
190
|
-
end
|
191
|
-
|
192
|
-
Haml::Engine.expects(:new).with('foo', {}).returns(stub(:render => 'foo'))
|
193
|
-
|
194
|
-
get_it '/'
|
195
|
-
should.be.ok
|
196
|
-
|
197
|
-
end
|
198
|
-
|
199
|
-
specify 'can be configured by passing :options to haml' do
|
200
|
-
|
201
|
-
get '/' do
|
202
|
-
haml 'foo', :options => {:format => :html4}
|
203
|
-
end
|
204
|
-
|
205
|
-
Haml::Engine.expects(:new).with('foo', {:format => :html4}).returns(stub(:render => 'foo'))
|
206
|
-
|
207
|
-
get_it '/'
|
208
|
-
should.be.ok
|
209
|
-
|
210
|
-
end
|
34
|
+
it "renders with file layouts" do
|
35
|
+
haml_app {
|
36
|
+
haml 'Hello World', :layout => :layout2
|
37
|
+
}
|
38
|
+
assert ok?
|
39
|
+
assert_equal "<h1>HAML Layout!</h1>\n<p>Hello World</p>\n", body
|
40
|
+
end
|
211
41
|
|
212
|
-
|
42
|
+
it "raises error if template not found" do
|
43
|
+
mock_app {
|
44
|
+
get('/') { haml :no_such_template }
|
45
|
+
}
|
46
|
+
assert_raise(Errno::ENOENT) { get('/') }
|
47
|
+
end
|
213
48
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
49
|
+
it "passes HAML options to the Haml engine" do
|
50
|
+
haml_app {
|
51
|
+
haml "!!!\n%h1 Hello World", :options => {:format => :html5}
|
52
|
+
}
|
53
|
+
assert ok?
|
54
|
+
assert_equal "<!DOCTYPE html>\n<h1>Hello World</h1>\n", body
|
55
|
+
end
|
218
56
|
|
57
|
+
it "passes default HAML options to the Haml engine" do
|
58
|
+
mock_app {
|
59
|
+
set :haml, {:format => :html5}
|
219
60
|
get '/' do
|
220
|
-
haml
|
61
|
+
haml "!!!\n%h1 Hello World"
|
221
62
|
end
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
get_it '/'
|
227
|
-
should.be.ok
|
228
|
-
|
229
|
-
end
|
230
|
-
|
63
|
+
}
|
64
|
+
get '/'
|
65
|
+
assert ok?
|
66
|
+
assert_equal "<!DOCTYPE html>\n<h1>Hello World</h1>\n", body
|
231
67
|
end
|
232
|
-
|
233
68
|
end
|
data/test/helper.rb
CHANGED
@@ -1,9 +1,25 @@
|
|
1
|
-
|
2
|
-
require '
|
1
|
+
begin
|
2
|
+
require 'test/spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
require 'test/spec'
|
6
|
+
end
|
3
7
|
|
4
|
-
|
8
|
+
$:.unshift File.dirname(File.dirname(__FILE__)) + '/lib'
|
9
|
+
require 'sinatra/base'
|
10
|
+
require 'sinatra/test'
|
11
|
+
require 'sinatra/test/spec'
|
5
12
|
|
6
|
-
|
13
|
+
module Sinatra::Test
|
14
|
+
# Sets up a Sinatra::Base subclass defined with the block
|
15
|
+
# given. Used in setup or individual spec methods to establish
|
16
|
+
# the application.
|
17
|
+
def mock_app(base=Sinatra::Base, &block)
|
18
|
+
@app = Sinatra.new(base, &block)
|
19
|
+
end
|
20
|
+
end
|
7
21
|
|
8
|
-
|
9
|
-
|
22
|
+
class Sinatra::Base
|
23
|
+
# Allow assertions in request context
|
24
|
+
include Test::Unit::Assertions
|
25
|
+
end
|
@@ -0,0 +1,361 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
describe 'Sinatra::Helpers' do
|
4
|
+
describe '#status' do
|
5
|
+
setup do
|
6
|
+
mock_app {
|
7
|
+
get '/' do
|
8
|
+
status 207
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'sets the response status code' do
|
15
|
+
get '/'
|
16
|
+
assert_equal 207, response.status
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
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
|
+
}
|
27
|
+
|
28
|
+
get '/'
|
29
|
+
assert_equal 'Hello World', body
|
30
|
+
end
|
31
|
+
|
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
|
+
}
|
38
|
+
|
39
|
+
get '/'
|
40
|
+
assert_equal 'Hello World', body
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
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
|
+
end
|
73
|
+
|
74
|
+
describe '#error' do
|
75
|
+
it 'sets a status code and halts' do
|
76
|
+
mock_app {
|
77
|
+
get '/' do
|
78
|
+
error 501
|
79
|
+
fail 'error should halt'
|
80
|
+
end
|
81
|
+
}
|
82
|
+
|
83
|
+
get '/'
|
84
|
+
assert_equal 501, status
|
85
|
+
assert_equal '', body
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'takes an optional body' do
|
89
|
+
mock_app {
|
90
|
+
get '/' do
|
91
|
+
error 501, 'FAIL'
|
92
|
+
fail 'error should halt'
|
93
|
+
end
|
94
|
+
}
|
95
|
+
|
96
|
+
get '/'
|
97
|
+
assert_equal 501, status
|
98
|
+
assert_equal 'FAIL', body
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'uses a 500 status code when first argument is a body' do
|
102
|
+
mock_app {
|
103
|
+
get '/' do
|
104
|
+
error 'FAIL'
|
105
|
+
fail 'error should halt'
|
106
|
+
end
|
107
|
+
}
|
108
|
+
|
109
|
+
get '/'
|
110
|
+
assert_equal 500, status
|
111
|
+
assert_equal 'FAIL', body
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#not_found' do
|
116
|
+
it 'halts with a 404 status' do
|
117
|
+
mock_app {
|
118
|
+
get '/' do
|
119
|
+
not_found
|
120
|
+
fail 'not_found should halt'
|
121
|
+
end
|
122
|
+
}
|
123
|
+
|
124
|
+
get '/'
|
125
|
+
assert_equal 404, status
|
126
|
+
assert_equal '', body
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#session' do
|
131
|
+
it 'uses the existing rack.session' do
|
132
|
+
mock_app {
|
133
|
+
get '/' do
|
134
|
+
session[:foo]
|
135
|
+
end
|
136
|
+
}
|
137
|
+
|
138
|
+
get '/', :env => { 'rack.session' => { :foo => 'bar' } }
|
139
|
+
assert_equal 'bar', body
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'creates a new session when none provided' do
|
143
|
+
mock_app {
|
144
|
+
get '/' do
|
145
|
+
assert session.empty?
|
146
|
+
session[:foo] = 'bar'
|
147
|
+
'Hi'
|
148
|
+
end
|
149
|
+
}
|
150
|
+
|
151
|
+
get '/'
|
152
|
+
assert_equal 'Hi', body
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#media_type' do
|
157
|
+
include Sinatra::Helpers
|
158
|
+
it "looks up media types in Rack's MIME registry" do
|
159
|
+
Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
|
160
|
+
assert_equal 'application/foo', media_type('foo')
|
161
|
+
assert_equal 'application/foo', media_type('.foo')
|
162
|
+
assert_equal 'application/foo', media_type(:foo)
|
163
|
+
end
|
164
|
+
it 'returns nil when given nil' do
|
165
|
+
assert media_type(nil).nil?
|
166
|
+
end
|
167
|
+
it 'returns nil when media type not registered' do
|
168
|
+
assert media_type(:bizzle).nil?
|
169
|
+
end
|
170
|
+
it 'returns the argument when given a media type string' do
|
171
|
+
assert_equal 'text/plain', media_type('text/plain')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#content_type' do
|
176
|
+
it 'sets the Content-Type header' do
|
177
|
+
mock_app {
|
178
|
+
get '/' do
|
179
|
+
content_type 'text/plain'
|
180
|
+
'Hello World'
|
181
|
+
end
|
182
|
+
}
|
183
|
+
|
184
|
+
get '/'
|
185
|
+
assert_equal 'text/plain', response['Content-Type']
|
186
|
+
assert_equal 'Hello World', body
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'takes media type parameters (like charset=)' do
|
190
|
+
mock_app {
|
191
|
+
get '/' do
|
192
|
+
content_type 'text/html', :charset => 'utf-8'
|
193
|
+
"<h1>Hello, World</h1>"
|
194
|
+
end
|
195
|
+
}
|
196
|
+
|
197
|
+
get '/'
|
198
|
+
assert ok?
|
199
|
+
assert_equal 'text/html;charset=utf-8', response['Content-Type']
|
200
|
+
assert_equal "<h1>Hello, World</h1>", body
|
201
|
+
end
|
202
|
+
|
203
|
+
it "looks up symbols in Rack's mime types dictionary" do
|
204
|
+
Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
|
205
|
+
mock_app {
|
206
|
+
get '/foo.xml' do
|
207
|
+
content_type :foo
|
208
|
+
"I AM FOO"
|
209
|
+
end
|
210
|
+
}
|
211
|
+
|
212
|
+
get '/foo.xml'
|
213
|
+
assert ok?
|
214
|
+
assert_equal 'application/foo', response['Content-Type']
|
215
|
+
assert_equal 'I AM FOO', body
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'fails when no mime type is registered for the argument provided' do
|
219
|
+
mock_app {
|
220
|
+
get '/foo.xml' do
|
221
|
+
content_type :bizzle
|
222
|
+
"I AM FOO"
|
223
|
+
end
|
224
|
+
}
|
225
|
+
assert_raise(RuntimeError) { get '/foo.xml' }
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe '#send_file' do
|
230
|
+
before {
|
231
|
+
@file = File.dirname(__FILE__) + '/file.txt'
|
232
|
+
File.open(@file, 'wb') { |io| io.write('Hello World') }
|
233
|
+
}
|
234
|
+
after {
|
235
|
+
File.unlink @file
|
236
|
+
@file = nil
|
237
|
+
}
|
238
|
+
|
239
|
+
def send_file_app
|
240
|
+
path = @file
|
241
|
+
mock_app {
|
242
|
+
get '/file.txt' do
|
243
|
+
send_file path
|
244
|
+
end
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
it "sends the contents of the file" do
|
249
|
+
send_file_app
|
250
|
+
get '/file.txt'
|
251
|
+
assert ok?
|
252
|
+
assert_equal 'Hello World', body
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'sets the Content-Type response header if a mime-type can be located' do
|
256
|
+
send_file_app
|
257
|
+
get '/file.txt'
|
258
|
+
assert_equal 'text/plain', response['Content-Type']
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'sets the Content-Length response header' do
|
262
|
+
send_file_app
|
263
|
+
get '/file.txt'
|
264
|
+
assert_equal 'Hello World'.length.to_s, response['Content-Length']
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'sets the Last-Modified response header' do
|
268
|
+
send_file_app
|
269
|
+
get '/file.txt'
|
270
|
+
assert_equal File.mtime(@file).httpdate, response['Last-Modified']
|
271
|
+
end
|
272
|
+
|
273
|
+
it "returns a 404 when not found" do
|
274
|
+
mock_app {
|
275
|
+
get '/' do
|
276
|
+
send_file 'this-file-does-not-exist.txt'
|
277
|
+
end
|
278
|
+
}
|
279
|
+
get '/'
|
280
|
+
assert not_found?
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe '#last_modified' do
|
285
|
+
before do
|
286
|
+
now = Time.now
|
287
|
+
mock_app {
|
288
|
+
get '/' do
|
289
|
+
body { 'Hello World' }
|
290
|
+
last_modified now
|
291
|
+
'Boo!'
|
292
|
+
end
|
293
|
+
}
|
294
|
+
@now = now
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
|
298
|
+
get '/'
|
299
|
+
assert_equal @now.httpdate, response['Last-Modified']
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'returns a body when conditional get misses' do
|
303
|
+
get '/'
|
304
|
+
assert_equal 200, status
|
305
|
+
assert_equal 'Boo!', body
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'halts when a conditional GET matches' do
|
309
|
+
get '/', :env => { 'HTTP_IF_MODIFIED_SINCE' => @now.httpdate }
|
310
|
+
assert_equal 304, status
|
311
|
+
assert_equal '', body
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
describe '#etag' do
|
316
|
+
before do
|
317
|
+
mock_app {
|
318
|
+
get '/' do
|
319
|
+
body { 'Hello World' }
|
320
|
+
etag 'FOO'
|
321
|
+
'Boo!'
|
322
|
+
end
|
323
|
+
}
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'sets the ETag header' do
|
327
|
+
get '/'
|
328
|
+
assert_equal '"FOO"', response['ETag']
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'returns a body when conditional get misses' do
|
332
|
+
get '/'
|
333
|
+
assert_equal 200, status
|
334
|
+
assert_equal 'Boo!', body
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'halts when a conditional GET matches' do
|
338
|
+
get '/', :env => { 'HTTP_IF_NONE_MATCH' => '"FOO"' }
|
339
|
+
assert_equal 304, status
|
340
|
+
assert_equal '', body
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'should handle multiple ETag values in If-None-Match header' do
|
344
|
+
get '/', :env => { 'HTTP_IF_NONE_MATCH' => '"BAR", *' }
|
345
|
+
assert_equal 304, status
|
346
|
+
assert_equal '', body
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'uses a weak etag with the :weak option' do
|
350
|
+
mock_app {
|
351
|
+
get '/' do
|
352
|
+
etag 'FOO', :weak
|
353
|
+
"that's weak, dude."
|
354
|
+
end
|
355
|
+
}
|
356
|
+
get '/'
|
357
|
+
assert_equal 'W/"FOO"', response['ETag']
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
end
|