roda 3.28.0 → 3.29.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +10 -0
- data/README.rdoc +10 -0
- data/doc/release_notes/3.29.0.txt +15 -0
- data/lib/roda.rb +1 -0
- data/lib/roda/plugins/caching.rb +2 -0
- data/lib/roda/plugins/common_logger.rb +1 -1
- data/lib/roda/plugins/exception_page.rb +7 -1
- data/lib/roda/plugins/indifferent_params.rb +2 -0
- data/lib/roda/version.rb +1 -1
- metadata +4 -214
- data/Rakefile +0 -108
- data/doc/release_notes/1.0.0.txt +0 -329
- data/doc/release_notes/1.1.0.txt +0 -226
- data/doc/release_notes/1.2.0.txt +0 -406
- data/doc/release_notes/1.3.0.txt +0 -109
- data/doc/release_notes/2.0.0.txt +0 -75
- data/doc/release_notes/2.1.0.txt +0 -124
- data/doc/release_notes/2.10.0.txt +0 -27
- data/doc/release_notes/2.11.0.txt +0 -70
- data/doc/release_notes/2.12.0.txt +0 -40
- data/doc/release_notes/2.13.0.txt +0 -10
- data/doc/release_notes/2.14.0.txt +0 -44
- data/doc/release_notes/2.15.0.txt +0 -53
- data/doc/release_notes/2.16.0.txt +0 -48
- data/doc/release_notes/2.17.0.txt +0 -62
- data/doc/release_notes/2.18.0.txt +0 -69
- data/doc/release_notes/2.19.0.txt +0 -30
- data/doc/release_notes/2.2.0.txt +0 -97
- data/doc/release_notes/2.20.0.txt +0 -5
- data/doc/release_notes/2.21.0.txt +0 -17
- data/doc/release_notes/2.22.0.txt +0 -41
- data/doc/release_notes/2.23.0.txt +0 -29
- data/doc/release_notes/2.24.0.txt +0 -65
- data/doc/release_notes/2.25.0.txt +0 -14
- data/doc/release_notes/2.26.0.txt +0 -13
- data/doc/release_notes/2.27.0.txt +0 -56
- data/doc/release_notes/2.28.0.txt +0 -17
- data/doc/release_notes/2.29.0.txt +0 -156
- data/doc/release_notes/2.3.0.txt +0 -109
- data/doc/release_notes/2.4.0.txt +0 -55
- data/doc/release_notes/2.5.0.txt +0 -23
- data/doc/release_notes/2.5.1.txt +0 -4
- data/doc/release_notes/2.6.0.txt +0 -21
- data/doc/release_notes/2.7.0.txt +0 -75
- data/doc/release_notes/2.8.0.txt +0 -44
- data/doc/release_notes/2.9.0.txt +0 -6
- data/spec/all.rb +0 -1
- data/spec/assets/css/app.scss +0 -1
- data/spec/assets/css/no_access.css +0 -1
- data/spec/assets/css/raw.css +0 -1
- data/spec/assets/js/head/app.js +0 -1
- data/spec/composition_spec.rb +0 -31
- data/spec/define_roda_method_spec.rb +0 -274
- data/spec/env_spec.rb +0 -11
- data/spec/freeze_spec.rb +0 -37
- data/spec/integration_spec.rb +0 -209
- data/spec/matchers_spec.rb +0 -832
- data/spec/opts_spec.rb +0 -42
- data/spec/plugin/_after_hook_spec.rb +0 -19
- data/spec/plugin/all_verbs_spec.rb +0 -29
- data/spec/plugin/assets_preloading_spec.rb +0 -98
- data/spec/plugin/assets_spec.rb +0 -745
- data/spec/plugin/backtracking_array_spec.rb +0 -42
- data/spec/plugin/branch_locals_spec.rb +0 -106
- data/spec/plugin/caching_spec.rb +0 -337
- data/spec/plugin/chunked_spec.rb +0 -201
- data/spec/plugin/class_level_routing_spec.rb +0 -164
- data/spec/plugin/class_matchers_spec.rb +0 -40
- data/spec/plugin/common_logger_spec.rb +0 -85
- data/spec/plugin/content_for_spec.rb +0 -162
- data/spec/plugin/content_security_policy_spec.rb +0 -175
- data/spec/plugin/cookies_spec.rb +0 -51
- data/spec/plugin/csrf_spec.rb +0 -111
- data/spec/plugin/default_headers_spec.rb +0 -82
- data/spec/plugin/default_status_spec.rb +0 -95
- data/spec/plugin/delay_build_spec.rb +0 -23
- data/spec/plugin/delegate_spec.rb +0 -23
- data/spec/plugin/delete_empty_headers_spec.rb +0 -27
- data/spec/plugin/direct_call_spec.rb +0 -28
- data/spec/plugin/disallow_file_uploads_spec.rb +0 -25
- data/spec/plugin/drop_body_spec.rb +0 -24
- data/spec/plugin/early_hints_spec.rb +0 -19
- data/spec/plugin/empty_root_spec.rb +0 -14
- data/spec/plugin/environments_spec.rb +0 -42
- data/spec/plugin/error_email_spec.rb +0 -97
- data/spec/plugin/error_handler_spec.rb +0 -216
- data/spec/plugin/error_mail_spec.rb +0 -93
- data/spec/plugin/exception_page_spec.rb +0 -168
- data/spec/plugin/flash_spec.rb +0 -121
- data/spec/plugin/h_spec.rb +0 -11
- data/spec/plugin/halt_spec.rb +0 -119
- data/spec/plugin/hash_matcher_spec.rb +0 -27
- data/spec/plugin/hash_routes_spec.rb +0 -535
- data/spec/plugin/head_spec.rb +0 -52
- data/spec/plugin/header_matchers_spec.rb +0 -98
- data/spec/plugin/heartbeat_spec.rb +0 -74
- data/spec/plugin/hooks_spec.rb +0 -152
- data/spec/plugin/indifferent_params_spec.rb +0 -14
- data/spec/plugin/json_parser_spec.rb +0 -141
- data/spec/plugin/json_spec.rb +0 -83
- data/spec/plugin/mail_processor_spec.rb +0 -451
- data/spec/plugin/mailer_spec.rb +0 -282
- data/spec/plugin/match_affix_spec.rb +0 -43
- data/spec/plugin/match_hook_spec.rb +0 -79
- data/spec/plugin/middleware_spec.rb +0 -237
- data/spec/plugin/middleware_stack_spec.rb +0 -81
- data/spec/plugin/module_include_spec.rb +0 -48
- data/spec/plugin/multi_route_spec.rb +0 -268
- data/spec/plugin/multi_run_spec.rb +0 -87
- data/spec/plugin/multi_view_spec.rb +0 -50
- data/spec/plugin/multibyte_string_matcher_spec.rb +0 -44
- data/spec/plugin/named_templates_spec.rb +0 -96
- data/spec/plugin/not_allowed_spec.rb +0 -69
- data/spec/plugin/not_found_spec.rb +0 -128
- data/spec/plugin/optimized_string_matchers_spec.rb +0 -43
- data/spec/plugin/padrino_render_spec.rb +0 -34
- data/spec/plugin/param_matchers_spec.rb +0 -69
- data/spec/plugin/params_capturing_spec.rb +0 -33
- data/spec/plugin/partials_spec.rb +0 -43
- data/spec/plugin/pass_spec.rb +0 -29
- data/spec/plugin/path_matchers_spec.rb +0 -42
- data/spec/plugin/path_rewriter_spec.rb +0 -45
- data/spec/plugin/path_spec.rb +0 -222
- data/spec/plugin/placeholder_string_matchers_spec.rb +0 -126
- data/spec/plugin/precompile_templates_spec.rb +0 -61
- data/spec/plugin/public_spec.rb +0 -85
- data/spec/plugin/render_each_spec.rb +0 -82
- data/spec/plugin/render_locals_spec.rb +0 -114
- data/spec/plugin/render_spec.rb +0 -912
- data/spec/plugin/request_aref_spec.rb +0 -51
- data/spec/plugin/request_headers_spec.rb +0 -39
- data/spec/plugin/response_request_spec.rb +0 -43
- data/spec/plugin/route_block_args_spec.rb +0 -86
- data/spec/plugin/route_csrf_spec.rb +0 -305
- data/spec/plugin/run_append_slash_spec.rb +0 -77
- data/spec/plugin/run_handler_spec.rb +0 -53
- data/spec/plugin/sessions_spec.rb +0 -452
- data/spec/plugin/shared_vars_spec.rb +0 -45
- data/spec/plugin/sinatra_helpers_spec.rb +0 -537
- data/spec/plugin/slash_path_empty_spec.rb +0 -22
- data/spec/plugin/static_routing_spec.rb +0 -192
- data/spec/plugin/static_spec.rb +0 -30
- data/spec/plugin/status_303_spec.rb +0 -28
- data/spec/plugin/status_handler_spec.rb +0 -158
- data/spec/plugin/streaming_spec.rb +0 -246
- data/spec/plugin/strip_path_prefix_spec.rb +0 -24
- data/spec/plugin/symbol_matchers_spec.rb +0 -51
- data/spec/plugin/symbol_status_spec.rb +0 -25
- data/spec/plugin/symbol_views_spec.rb +0 -32
- data/spec/plugin/timestamp_public_spec.rb +0 -85
- data/spec/plugin/type_routing_spec.rb +0 -348
- data/spec/plugin/typecast_params_spec.rb +0 -1370
- data/spec/plugin/unescape_path_spec.rb +0 -22
- data/spec/plugin/view_options_spec.rb +0 -170
- data/spec/plugin_spec.rb +0 -71
- data/spec/redirect_spec.rb +0 -41
- data/spec/request_spec.rb +0 -97
- data/spec/response_spec.rb +0 -199
- data/spec/route_spec.rb +0 -39
- data/spec/session_middleware_spec.rb +0 -129
- data/spec/session_spec.rb +0 -37
- data/spec/spec_helper.rb +0 -137
- data/spec/version_spec.rb +0 -14
- data/spec/views/_test.erb +0 -1
- data/spec/views/a.erb +0 -1
- data/spec/views/a.rdoc +0 -2
- data/spec/views/about.erb +0 -1
- data/spec/views/about.str +0 -1
- data/spec/views/about/_test.css.gz +0 -0
- data/spec/views/about/_test.erb +0 -1
- data/spec/views/about/_test.erb.gz +0 -0
- data/spec/views/about/comp_test.erb +0 -1
- data/spec/views/b.erb +0 -1
- data/spec/views/c.erb +0 -1
- data/spec/views/comp_layout.erb +0 -1
- data/spec/views/comp_test.erb +0 -1
- data/spec/views/content-yield.erb +0 -1
- data/spec/views/each.str +0 -1
- data/spec/views/home.erb +0 -2
- data/spec/views/home.str +0 -2
- data/spec/views/iv.erb +0 -1
- data/spec/views/layout-alternative.erb +0 -2
- data/spec/views/layout-yield.erb +0 -3
- data/spec/views/layout.erb +0 -2
- data/spec/views/layout.str +0 -2
- data/spec/views/multiple-layout.erb +0 -1
- data/spec/views/multiple.erb +0 -1
@@ -1,45 +0,0 @@
|
|
1
|
-
require_relative "../spec_helper"
|
2
|
-
|
3
|
-
describe "shared_vars plugin" do
|
4
|
-
it "adds shared method for sharing variables across multiple apps" do
|
5
|
-
app(:shared_vars) {|r| shared[:c]}
|
6
|
-
old_app = app
|
7
|
-
app(:shared_vars) do |r|
|
8
|
-
shared[:c] = 'c'
|
9
|
-
r.run old_app
|
10
|
-
end
|
11
|
-
|
12
|
-
body.must_equal 'c'
|
13
|
-
end
|
14
|
-
|
15
|
-
it "adds shared with hash merges the hash into the shared vars" do
|
16
|
-
app(:shared_vars) do |r|
|
17
|
-
shared(:c=>'c')
|
18
|
-
shared[:c]
|
19
|
-
end
|
20
|
-
|
21
|
-
body.must_equal 'c'
|
22
|
-
end
|
23
|
-
|
24
|
-
it "calling shared with hash and a block sets shared variables only for that block" do
|
25
|
-
app(:shared_vars) do |r|
|
26
|
-
c = nil
|
27
|
-
d = nil
|
28
|
-
shared[:c] = 'b'
|
29
|
-
shared(:c=>'c', :d=>'d') do
|
30
|
-
c = shared[:c]
|
31
|
-
d = shared[:d]
|
32
|
-
end
|
33
|
-
"#{shared[:c]}:#{shared[:d]}:#{c}:#{d}"
|
34
|
-
end
|
35
|
-
|
36
|
-
body.must_equal 'b::c:d'
|
37
|
-
end
|
38
|
-
|
39
|
-
it "calling shared with no arguments and a block raises an error" do
|
40
|
-
app(:shared_vars) do |r|
|
41
|
-
shared{}
|
42
|
-
end
|
43
|
-
proc{body}.must_raise(Roda::RodaError)
|
44
|
-
end
|
45
|
-
end
|
@@ -1,537 +0,0 @@
|
|
1
|
-
require_relative "../spec_helper"
|
2
|
-
|
3
|
-
require 'uri'
|
4
|
-
|
5
|
-
describe "sinatra_helpers plugin" do
|
6
|
-
def sin_app(&block)
|
7
|
-
app(:sinatra_helpers, &block)
|
8
|
-
end
|
9
|
-
|
10
|
-
def status_app(code, &block)
|
11
|
-
block ||= proc{}
|
12
|
-
sin_app do |r|
|
13
|
-
status code
|
14
|
-
instance_eval(&block).inspect
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'status returns the response status code if not given an argument' do
|
19
|
-
status_app(207){status}
|
20
|
-
body.must_equal "207"
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'status sets the response status code if given an argument' do
|
24
|
-
status_app 207
|
25
|
-
status.must_equal 207
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'not_found? is true only if status == 404' do
|
29
|
-
status_app(404){not_found?}
|
30
|
-
body.must_equal 'true'
|
31
|
-
status_app(405){not_found?}
|
32
|
-
body.must_equal 'false'
|
33
|
-
status_app(403){not_found?}
|
34
|
-
body.must_equal 'false'
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'informational? is true only for 1xx status' do
|
38
|
-
status_app(100 + rand(100)){informational?}
|
39
|
-
body.must_equal 'true'
|
40
|
-
status_app(200 + rand(400)){informational?}
|
41
|
-
body.must_equal 'false'
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'success? is true only for 2xx status' do
|
45
|
-
status_app(200 + rand(100)){success?}
|
46
|
-
body.must_equal 'true'
|
47
|
-
status_app(100 + rand(100)){success?}
|
48
|
-
body.must_equal 'false'
|
49
|
-
status_app(300 + rand(300)){success?}
|
50
|
-
body.must_equal 'false'
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'redirect? is true only for 3xx status' do
|
54
|
-
status_app(300 + rand(100)){redirect?}
|
55
|
-
body.must_equal 'true'
|
56
|
-
status_app(200 + rand(100)){redirect?}
|
57
|
-
body.must_equal 'false'
|
58
|
-
status_app(400 + rand(200)){redirect?}
|
59
|
-
body.must_equal 'false'
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'client_error? is true only for 4xx status' do
|
63
|
-
status_app(400 + rand(100)){client_error?}
|
64
|
-
body.must_equal 'true'
|
65
|
-
status_app(200 + rand(200)){client_error?}
|
66
|
-
body.must_equal 'false'
|
67
|
-
status_app(500 + rand(100)){client_error?}
|
68
|
-
body.must_equal 'false'
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'server_error? is true only for 5xx status' do
|
72
|
-
status_app(500 + rand(100)){server_error?}
|
73
|
-
body.must_equal 'true'
|
74
|
-
status_app(200 + rand(300)){server_error?}
|
75
|
-
body.must_equal 'false'
|
76
|
-
end
|
77
|
-
|
78
|
-
describe 'body' do
|
79
|
-
it 'takes a block for deferred body generation' do
|
80
|
-
sin_app{body{'Hello World'}; nil}
|
81
|
-
body.must_equal 'Hello World'
|
82
|
-
header('Content-Length').must_equal '11'
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'supports #join' do
|
86
|
-
sin_app{body{'Hello World'}; nil}
|
87
|
-
req[2].join.must_equal 'Hello World'
|
88
|
-
end
|
89
|
-
|
90
|
-
it 'takes a String, Array, or other object responding to #each' do
|
91
|
-
sin_app{body 'Hello World'; nil}
|
92
|
-
body.must_equal 'Hello World'
|
93
|
-
header('Content-Length').must_equal '11'
|
94
|
-
|
95
|
-
sin_app{body ['Hello ', 'World']; nil}
|
96
|
-
body.must_equal 'Hello World'
|
97
|
-
header('Content-Length').must_equal '11'
|
98
|
-
|
99
|
-
o = Object.new
|
100
|
-
def o.each; yield 'Hello World' end
|
101
|
-
sin_app{body o; nil}
|
102
|
-
body.must_equal 'Hello World'
|
103
|
-
header('Content-Length').must_equal '11'
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
describe 'redirect' do
|
108
|
-
it 'uses a 302 when only a path is given' do
|
109
|
-
sin_app do
|
110
|
-
redirect '/foo'
|
111
|
-
fail 'redirect should halt'
|
112
|
-
end
|
113
|
-
|
114
|
-
status.must_equal 302
|
115
|
-
body.must_equal ''
|
116
|
-
header('Location').must_equal '/foo'
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'adds script_name if given a path' do
|
120
|
-
sin_app{redirect "/foo"}
|
121
|
-
header('Location', '/bar', 'SCRIPT_NAME'=>'/foo').must_equal '/foo'
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'does not adds script_name if not given a path' do
|
125
|
-
sin_app{redirect}
|
126
|
-
header('Location', '/bar', 'SCRIPT_NAME'=>'/foo', 'REQUEST_METHOD'=>'POST').must_equal '/foo/bar'
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'respects :absolute_redirects option' do
|
130
|
-
sin_app{redirect}
|
131
|
-
app.opts[:absolute_redirects] = true
|
132
|
-
header('Location', '/bar', 'HTTP_HOST'=>'example.org', 'SCRIPT_NAME'=>'/foo', 'REQUEST_METHOD'=>'POST').must_equal 'http://example.org/foo/bar'
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'respects :prefixed_redirects option' do
|
136
|
-
sin_app{redirect "/bar"}
|
137
|
-
app.opts[:prefixed_redirects] = true
|
138
|
-
header('Location', 'SCRIPT_NAME'=>'/foo').must_equal '/foo/bar'
|
139
|
-
end
|
140
|
-
|
141
|
-
it 'ignores :prefix_redirects option if not given a path' do
|
142
|
-
sin_app{redirect}
|
143
|
-
app.opts[:prefix_redirects] = true
|
144
|
-
header('Location', "/bar", 'SCRIPT_NAME'=>'/foo', 'REQUEST_METHOD'=>'POST').must_equal '/foo/bar'
|
145
|
-
end
|
146
|
-
|
147
|
-
it 'uses the code given when specified' do
|
148
|
-
sin_app{redirect '/foo', 301}
|
149
|
-
status.must_equal 301
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'redirects back to request.referer when passed back' do
|
153
|
-
sin_app{redirect back}
|
154
|
-
header('Location', 'HTTP_REFERER' => '/foo').must_equal '/foo'
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'uses 303 for post requests if request is HTTP 1.1, 302 for 1.0' do
|
158
|
-
sin_app{redirect '/foo'}
|
159
|
-
status('HTTP_VERSION' => 'HTTP/1.1', 'REQUEST_METHOD'=>'POST').must_equal 303
|
160
|
-
status('HTTP_VERSION' => 'HTTP/1.0', 'REQUEST_METHOD'=>'POST').must_equal 302
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
describe 'error' do
|
165
|
-
it 'sets a status code and halts' do
|
166
|
-
sin_app do
|
167
|
-
error
|
168
|
-
fail 'error should halt'
|
169
|
-
end
|
170
|
-
|
171
|
-
status.must_equal 500
|
172
|
-
body.must_equal ''
|
173
|
-
end
|
174
|
-
|
175
|
-
it 'accepts status code' do
|
176
|
-
sin_app{error 501}
|
177
|
-
status.must_equal 501
|
178
|
-
body.must_equal ''
|
179
|
-
end
|
180
|
-
|
181
|
-
it 'accepts body' do
|
182
|
-
sin_app{error '501'}
|
183
|
-
status.must_equal 500
|
184
|
-
body.must_equal '501'
|
185
|
-
end
|
186
|
-
|
187
|
-
it 'accepts status code and body' do
|
188
|
-
sin_app{error 502, '501'}
|
189
|
-
status.must_equal 502
|
190
|
-
body.must_equal '501'
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
describe 'not_found' do
|
195
|
-
it 'halts with a 404 status' do
|
196
|
-
sin_app do
|
197
|
-
not_found
|
198
|
-
fail 'not_found should halt'
|
199
|
-
end
|
200
|
-
|
201
|
-
status.must_equal 404
|
202
|
-
body.must_equal ''
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'accepts optional body' do
|
206
|
-
sin_app{not_found 'nf'}
|
207
|
-
status.must_equal 404
|
208
|
-
body.must_equal 'nf'
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
describe 'headers' do
|
213
|
-
it 'sets headers on the response object when given a Hash' do
|
214
|
-
sin_app do
|
215
|
-
headers 'X-Foo' => 'bar'
|
216
|
-
'kthx'
|
217
|
-
end
|
218
|
-
|
219
|
-
header('X-Foo').must_equal 'bar'
|
220
|
-
body.must_equal 'kthx'
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'returns the response headers hash when no hash provided' do
|
224
|
-
sin_app{headers['X-Foo'] = 'bar'}
|
225
|
-
header('X-Foo').must_equal 'bar'
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
describe 'mime_type' do
|
230
|
-
before do
|
231
|
-
sin_app{|r| mime_type((r.path unless r.path.empty?)).to_s}
|
232
|
-
end
|
233
|
-
|
234
|
-
it "looks up mime types in Rack's MIME registry" do
|
235
|
-
Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
|
236
|
-
body('foo').must_equal 'application/foo'
|
237
|
-
body('.foo').must_equal 'application/foo'
|
238
|
-
end
|
239
|
-
|
240
|
-
it 'returns nil when given nil' do
|
241
|
-
body('PATH_INFO'=>'').must_equal ''
|
242
|
-
end
|
243
|
-
|
244
|
-
it 'returns nil when media type not registered' do
|
245
|
-
body('bizzle').must_equal ''
|
246
|
-
end
|
247
|
-
|
248
|
-
it 'returns the argument when given a media type string' do
|
249
|
-
body('text/plain').must_equal 'text/plain'
|
250
|
-
end
|
251
|
-
|
252
|
-
it 'supports mime types registered at the class level' do
|
253
|
-
app.mime_type :foo, 'application/foo2'
|
254
|
-
body('foo').must_equal 'application/foo2'
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
describe 'content_type' do
|
259
|
-
it 'sets the Content-Type header' do
|
260
|
-
sin_app do
|
261
|
-
content_type 'text/plain'
|
262
|
-
'Hello World'
|
263
|
-
end
|
264
|
-
|
265
|
-
header('Content-Type').must_equal 'text/plain'
|
266
|
-
body.must_equal 'Hello World'
|
267
|
-
end
|
268
|
-
|
269
|
-
it 'takes media type parameters (like charset=)' do
|
270
|
-
sin_app{content_type 'text/html', :charset => 'latin1'}
|
271
|
-
header('Content-Type').must_equal 'text/html;charset=latin1'
|
272
|
-
end
|
273
|
-
|
274
|
-
it "looks up symbols in Rack's mime types dictionary" do
|
275
|
-
sin_app{content_type :foo}
|
276
|
-
Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
|
277
|
-
header('Content-Type').must_equal 'application/foo'
|
278
|
-
end
|
279
|
-
|
280
|
-
it 'fails when no mime type is registered for the argument provided' do
|
281
|
-
sin_app{content_type :bizzle}
|
282
|
-
proc{body}.must_raise(Roda::RodaError)
|
283
|
-
end
|
284
|
-
|
285
|
-
it 'handles already present params' do
|
286
|
-
sin_app{content_type 'foo/bar;level=1', :charset => 'utf-8'}
|
287
|
-
header('Content-Type').must_equal 'foo/bar;level=1, charset=utf-8'
|
288
|
-
end
|
289
|
-
|
290
|
-
it 'does not add charset if present' do
|
291
|
-
sin_app{content_type 'text/plain;charset=utf-16', :charset => 'utf-8'}
|
292
|
-
header('Content-Type').must_equal 'text/plain;charset=utf-16'
|
293
|
-
end
|
294
|
-
|
295
|
-
it 'properly encodes parameters with delimiter characters' do
|
296
|
-
sin_app{|r| content_type 'image/png', :comment => r.path }
|
297
|
-
header('Content-Type', 'Hello, world!').must_equal 'image/png;comment="Hello, world!"'
|
298
|
-
header('Content-Type', 'semi;colon').must_equal 'image/png;comment="semi;colon"'
|
299
|
-
header('Content-Type', '"Whatever."').must_equal 'image/png;comment="\"Whatever.\""'
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
describe 'attachment' do
|
304
|
-
before do
|
305
|
-
sin_app{|r| attachment r.path; 'b'}
|
306
|
-
end
|
307
|
-
|
308
|
-
it 'sets the Content-Disposition header' do
|
309
|
-
header('Content-Disposition', '/foo/test.xml').must_equal 'attachment; filename="test.xml"'
|
310
|
-
body.must_equal 'b'
|
311
|
-
end
|
312
|
-
|
313
|
-
it 'sets the Content-Disposition header even when a filename is not given' do
|
314
|
-
sin_app{attachment}
|
315
|
-
header('Content-Disposition', '/foo/test.xml').must_equal 'attachment'
|
316
|
-
end
|
317
|
-
|
318
|
-
it 'sets the Content-Type header' do
|
319
|
-
header('Content-Type', 'test.xml').must_equal 'application/xml'
|
320
|
-
end
|
321
|
-
|
322
|
-
it 'does not modify the default Content-Type without a file extension' do
|
323
|
-
header('Content-Type', 'README').must_equal 'text/html'
|
324
|
-
end
|
325
|
-
|
326
|
-
it 'should not modify the Content-Type if it is already set' do
|
327
|
-
sin_app do
|
328
|
-
content_type :atom
|
329
|
-
attachment 'test.xml'
|
330
|
-
end
|
331
|
-
|
332
|
-
header('Content-Type', 'README').must_equal 'application/atom+xml'
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
describe 'send_file' do
|
337
|
-
before(:all) do
|
338
|
-
file = @file = 'spec/assets/css/raw.css'
|
339
|
-
@content = File.read(@file)
|
340
|
-
sin_app{send_file file, env['OPTS'] || {}}
|
341
|
-
end
|
342
|
-
|
343
|
-
it "sends the contents of the file" do
|
344
|
-
status.must_equal 200
|
345
|
-
body.must_equal @content
|
346
|
-
end
|
347
|
-
|
348
|
-
it 'sets the Content-Type response header if a mime-type can be located' do
|
349
|
-
header('Content-Type').must_equal 'text/css'
|
350
|
-
end
|
351
|
-
|
352
|
-
it 'sets the Content-Type response header if type option is set to a file extension' do
|
353
|
-
header('Content-Type', 'OPTS'=>{:type => 'html'}).must_equal 'text/html'
|
354
|
-
end
|
355
|
-
|
356
|
-
it 'sets the Content-Type response header if type option is set to a mime type' do
|
357
|
-
header('Content-Type', 'OPTS'=>{:type => 'application/octet-stream'}).must_equal 'application/octet-stream'
|
358
|
-
end
|
359
|
-
|
360
|
-
it 'sets the Content-Length response header' do
|
361
|
-
header('Content-Length').must_equal @content.length.to_s
|
362
|
-
end
|
363
|
-
|
364
|
-
it 'sets the Last-Modified response header' do
|
365
|
-
header('Last-Modified').must_equal File.mtime(@file).httpdate
|
366
|
-
end
|
367
|
-
|
368
|
-
it 'allows passing in a different Last-Modified response header with :last_modified' do
|
369
|
-
time = Time.now
|
370
|
-
@app.plugin :caching
|
371
|
-
header('Last-Modified', 'OPTS'=>{:last_modified => time}).must_equal time.httpdate
|
372
|
-
end
|
373
|
-
|
374
|
-
it "returns a 404 when not found" do
|
375
|
-
sin_app{send_file 'this-file-does-not-exist.txt'}
|
376
|
-
status.must_equal 404
|
377
|
-
end
|
378
|
-
|
379
|
-
it "does not set the Content-Disposition header by default" do
|
380
|
-
header('Content-Disposition').must_be_nil
|
381
|
-
end
|
382
|
-
|
383
|
-
it "sets the Content-Disposition header when :disposition set to 'attachment'" do
|
384
|
-
header('Content-Disposition', 'OPTS'=>{:disposition => 'attachment'}).must_equal 'attachment; filename="raw.css"'
|
385
|
-
end
|
386
|
-
|
387
|
-
it "does not set add a file name if filename is false" do
|
388
|
-
header('Content-Disposition', 'OPTS'=>{:disposition => 'inline', :filename=>false}).must_equal 'inline'
|
389
|
-
end
|
390
|
-
|
391
|
-
it "sets the Content-Disposition header when :disposition set to 'inline'" do
|
392
|
-
header('Content-Disposition', 'OPTS'=>{:disposition => 'inline'}).must_equal 'inline; filename="raw.css"'
|
393
|
-
end
|
394
|
-
|
395
|
-
it "sets the Content-Disposition header when :filename provided" do
|
396
|
-
header('Content-Disposition', 'OPTS'=>{:filename => 'foo.txt'}).must_equal 'attachment; filename="foo.txt"'
|
397
|
-
end
|
398
|
-
|
399
|
-
it 'allows setting a custom status code' do
|
400
|
-
status('OPTS'=>{:status=>201}).must_equal 201
|
401
|
-
end
|
402
|
-
|
403
|
-
it "is able to send files with unknown mime type" do
|
404
|
-
header('Content-Type', 'OPTS'=>{:type => '.foobar'}).must_equal 'application/octet-stream'
|
405
|
-
end
|
406
|
-
|
407
|
-
it "does not override Content-Type if already set and no explicit type is given" do
|
408
|
-
file = @file
|
409
|
-
sin_app do
|
410
|
-
content_type :png
|
411
|
-
send_file file
|
412
|
-
end
|
413
|
-
header('Content-Type').must_equal 'image/png'
|
414
|
-
end
|
415
|
-
|
416
|
-
it "does override Content-Type even if already set, if explicit type is given" do
|
417
|
-
file = @file
|
418
|
-
sin_app do
|
419
|
-
content_type :png
|
420
|
-
send_file file, :type => :gif
|
421
|
-
end
|
422
|
-
header('Content-Type').must_equal 'image/gif'
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
describe 'uri' do
|
427
|
-
describe "without arguments" do
|
428
|
-
before do
|
429
|
-
sin_app{uri}
|
430
|
-
end
|
431
|
-
|
432
|
-
it 'generates absolute urls' do
|
433
|
-
body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/'
|
434
|
-
end
|
435
|
-
|
436
|
-
it 'includes path_info' do
|
437
|
-
body('/foo', 'HTTP_HOST'=>'example.org').must_equal 'http://example.org/foo'
|
438
|
-
end
|
439
|
-
|
440
|
-
it 'includes script_name' do
|
441
|
-
body('/bar', 'HTTP_HOST'=>'example.org', "SCRIPT_NAME" => '/foo').must_equal 'http://example.org/foo/bar'
|
442
|
-
end
|
443
|
-
|
444
|
-
it 'handles standard HTTP and HTTPS ports' do
|
445
|
-
body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '80').must_equal 'http://example.org/'
|
446
|
-
body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '443', 'HTTPS'=>'on').must_equal 'https://example.org/'
|
447
|
-
end
|
448
|
-
|
449
|
-
it 'handles non-standard HTTP port' do
|
450
|
-
body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '81').must_equal 'http://example.org:81/'
|
451
|
-
body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '443').must_equal 'http://example.org:443/'
|
452
|
-
end
|
453
|
-
|
454
|
-
it 'handles non-standard HTTPS port' do
|
455
|
-
body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '444', 'HTTPS'=>'on').must_equal 'https://example.org:444/'
|
456
|
-
body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '80', 'HTTPS'=>'on').must_equal 'https://example.org:80/'
|
457
|
-
end
|
458
|
-
|
459
|
-
it 'handles reverse proxy' do
|
460
|
-
body('SERVER_NAME'=>'example.org', 'HTTP_X_FORWARDED_HOST' => 'example.com', 'SERVER_PORT' => '8080').must_equal 'http://example.com/'
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
it 'allows passing an alternative to path_info' do
|
465
|
-
sin_app{uri '/bar'}
|
466
|
-
body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/bar'
|
467
|
-
body('HTTP_HOST'=>'example.org', "SCRIPT_NAME" => '/foo').must_equal 'http://example.org/foo/bar'
|
468
|
-
end
|
469
|
-
|
470
|
-
it 'handles absolute URIs' do
|
471
|
-
sin_app{uri 'http://google.com'}
|
472
|
-
body('HTTP_HOST'=>'example.org').must_equal 'http://google.com'
|
473
|
-
end
|
474
|
-
|
475
|
-
it 'handles different protocols' do
|
476
|
-
sin_app{uri 'mailto:jsmith@example.com'}
|
477
|
-
body('HTTP_HOST'=>'example.org').must_equal 'mailto:jsmith@example.com'
|
478
|
-
end
|
479
|
-
|
480
|
-
it 'allows turning off host' do
|
481
|
-
sin_app{uri '/foo', false}
|
482
|
-
body('HTTP_HOST'=>'example.org').must_equal '/foo'
|
483
|
-
body('HTTP_HOST'=>'example.org', "SCRIPT_NAME" => '/bar').must_equal '/bar/foo'
|
484
|
-
end
|
485
|
-
|
486
|
-
it 'allows turning off script_name' do
|
487
|
-
sin_app{uri '/foo', true, false}
|
488
|
-
body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/foo'
|
489
|
-
body('HTTP_HOST'=>'example.org', "SCRIPT_NAME" => '/bar').must_equal 'http://example.org/foo'
|
490
|
-
end
|
491
|
-
|
492
|
-
it 'is aliased to #url' do
|
493
|
-
sin_app{url}
|
494
|
-
body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/'
|
495
|
-
end
|
496
|
-
|
497
|
-
it 'is aliased to #to' do
|
498
|
-
sin_app{to}
|
499
|
-
body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/'
|
500
|
-
end
|
501
|
-
|
502
|
-
it 'accepts a URI object instead of a String' do
|
503
|
-
sin_app{uri URI.parse('http://roda.jeremyevans.net')}
|
504
|
-
body.must_equal 'http://roda.jeremyevans.net'
|
505
|
-
end
|
506
|
-
end
|
507
|
-
|
508
|
-
it 'logger logs to rack.logger' do
|
509
|
-
sin_app{logger.info "foo"; nil}
|
510
|
-
o = Object.new
|
511
|
-
def o.method_missing(*a)
|
512
|
-
(@a ||= []) << a
|
513
|
-
end
|
514
|
-
def o.logs
|
515
|
-
@a
|
516
|
-
end
|
517
|
-
|
518
|
-
status('rack.logger'=>o).must_equal 404
|
519
|
-
o.logs.must_equal [[:info, 'foo']]
|
520
|
-
end
|
521
|
-
|
522
|
-
it 'supports disabling delegation if :delegate=>false option is provided' do
|
523
|
-
app(:bare) do
|
524
|
-
plugin :sinatra_helpers, :delegate=>false
|
525
|
-
route do |r|
|
526
|
-
r.root{content_type}
|
527
|
-
r.is("req"){r.ssl?.to_s}
|
528
|
-
r.is("res"){response.not_found?.inspect}
|
529
|
-
end
|
530
|
-
end
|
531
|
-
|
532
|
-
proc{body}.must_raise(NameError)
|
533
|
-
body('/req').must_equal 'false'
|
534
|
-
body('/res').must_equal 'nil'
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|