roda 3.28.0 → 3.29.0
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.
- 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
|
-
|