darkhelmet-sinatra 0.9.0.5

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.
Files changed (85) hide show
  1. data/AUTHORS +41 -0
  2. data/CHANGES +243 -0
  3. data/LICENSE +22 -0
  4. data/README.rdoc +535 -0
  5. data/Rakefile +136 -0
  6. data/compat/app_test.rb +301 -0
  7. data/compat/application_test.rb +334 -0
  8. data/compat/builder_test.rb +101 -0
  9. data/compat/compat_test.rb +12 -0
  10. data/compat/custom_error_test.rb +62 -0
  11. data/compat/erb_test.rb +136 -0
  12. data/compat/events_test.rb +78 -0
  13. data/compat/filter_test.rb +30 -0
  14. data/compat/haml_test.rb +233 -0
  15. data/compat/helper.rb +30 -0
  16. data/compat/mapped_error_test.rb +72 -0
  17. data/compat/pipeline_test.rb +71 -0
  18. data/compat/public/foo.xml +1 -0
  19. data/compat/sass_test.rb +57 -0
  20. data/compat/sessions_test.rb +39 -0
  21. data/compat/streaming_test.rb +133 -0
  22. data/compat/sym_params_test.rb +19 -0
  23. data/compat/template_test.rb +30 -0
  24. data/compat/use_in_file_templates_test.rb +47 -0
  25. data/compat/views/foo.builder +1 -0
  26. data/compat/views/foo.erb +1 -0
  27. data/compat/views/foo.haml +1 -0
  28. data/compat/views/foo.sass +2 -0
  29. data/compat/views/foo_layout.erb +2 -0
  30. data/compat/views/foo_layout.haml +2 -0
  31. data/compat/views/layout_test/foo.builder +1 -0
  32. data/compat/views/layout_test/foo.erb +1 -0
  33. data/compat/views/layout_test/foo.haml +1 -0
  34. data/compat/views/layout_test/foo.sass +2 -0
  35. data/compat/views/layout_test/layout.builder +3 -0
  36. data/compat/views/layout_test/layout.erb +1 -0
  37. data/compat/views/layout_test/layout.haml +1 -0
  38. data/compat/views/layout_test/layout.sass +2 -0
  39. data/compat/views/no_layout/no_layout.builder +1 -0
  40. data/compat/views/no_layout/no_layout.haml +1 -0
  41. data/lib/sinatra/base.rb +1007 -0
  42. data/lib/sinatra/compat.rb +252 -0
  43. data/lib/sinatra/images/404.png +0 -0
  44. data/lib/sinatra/images/500.png +0 -0
  45. data/lib/sinatra/main.rb +47 -0
  46. data/lib/sinatra/test/bacon.rb +19 -0
  47. data/lib/sinatra/test/rspec.rb +13 -0
  48. data/lib/sinatra/test/spec.rb +11 -0
  49. data/lib/sinatra/test/unit.rb +13 -0
  50. data/lib/sinatra/test.rb +121 -0
  51. data/lib/sinatra.rb +8 -0
  52. data/sinatra.gemspec +116 -0
  53. data/test/base_test.rb +112 -0
  54. data/test/builder_test.rb +64 -0
  55. data/test/data/reload_app_file.rb +3 -0
  56. data/test/erb_test.rb +81 -0
  57. data/test/extensions_test.rb +63 -0
  58. data/test/filter_test.rb +99 -0
  59. data/test/haml_test.rb +68 -0
  60. data/test/helper.rb +85 -0
  61. data/test/helpers_test.rb +467 -0
  62. data/test/mapped_error_test.rb +160 -0
  63. data/test/middleware_test.rb +60 -0
  64. data/test/options_test.rb +374 -0
  65. data/test/reload_test.rb +68 -0
  66. data/test/request_test.rb +18 -0
  67. data/test/response_test.rb +42 -0
  68. data/test/result_test.rb +98 -0
  69. data/test/routing_test.rb +712 -0
  70. data/test/sass_test.rb +36 -0
  71. data/test/server_test.rb +41 -0
  72. data/test/sinatra_test.rb +13 -0
  73. data/test/static_test.rb +65 -0
  74. data/test/templates_test.rb +88 -0
  75. data/test/test_test.rb +109 -0
  76. data/test/views/hello.builder +1 -0
  77. data/test/views/hello.erb +1 -0
  78. data/test/views/hello.haml +1 -0
  79. data/test/views/hello.sass +2 -0
  80. data/test/views/hello.test +1 -0
  81. data/test/views/layout2.builder +3 -0
  82. data/test/views/layout2.erb +2 -0
  83. data/test/views/layout2.haml +2 -0
  84. data/test/views/layout2.test +1 -0
  85. metadata +184 -0
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ $reload_count = 0
4
+ $reload_app = nil
5
+
6
+ describe "Reloading" do
7
+ before {
8
+ @app = mock_app(Sinatra::Default)
9
+ $reload_app = @app
10
+ }
11
+
12
+ after {
13
+ $reload_app = nil
14
+ }
15
+
16
+ it 'is enabled by default when in development and the app_file is set' do
17
+ @app.set :app_file, __FILE__
18
+ @app.set :environment, :development
19
+ assert_same true, @app.reload
20
+ assert_same true, @app.reload?
21
+ end
22
+
23
+ it 'is disabled by default when running in non-development environment' do
24
+ @app.set :app_file, __FILE__
25
+ @app.set :environment, :test
26
+ assert !@app.reload
27
+ assert_same false, @app.reload?
28
+ end
29
+
30
+ it 'is disabled by default when no app_file is available' do
31
+ @app.set :app_file, nil
32
+ @app.set :environment, :development
33
+ assert !@app.reload
34
+ assert_same false, @app.reload?
35
+ end
36
+
37
+ it 'is disabled when app_file is a rackup (.ru) file' do
38
+ @app.set :app_file, __FILE__.sub(/\.rb$/, '.ru')
39
+ @app.set :environment, :development
40
+ assert !@app.reload
41
+ assert_same false, @app.reload?
42
+ end
43
+
44
+ it 'can be turned off explicitly' do
45
+ @app.set :app_file, __FILE__
46
+ @app.set :environment, :development
47
+ assert_same true, @app.reload
48
+ @app.set :reload, false
49
+ assert_same false, @app.reload
50
+ assert_same false, @app.reload?
51
+ end
52
+
53
+ it 'reloads the app_file each time a request is made' do
54
+ @app.set :app_file, File.dirname(__FILE__) + '/data/reload_app_file.rb'
55
+ @app.set :reload, true
56
+ @app.get('/') { 'Hello World' }
57
+
58
+ get '/'
59
+ assert_equal 200, status
60
+ assert_equal 'Hello from reload file', body
61
+ assert_equal 1, $reload_count
62
+
63
+ get '/'
64
+ assert_equal 200, status
65
+ assert_equal 'Hello from reload file', body
66
+ assert_equal 2, $reload_count
67
+ end
68
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ describe 'Sinatra::Request' do
4
+ it 'responds to #user_agent' do
5
+ request = Sinatra::Request.new({'HTTP_USER_AGENT' => 'Test'})
6
+ assert request.respond_to?(:user_agent)
7
+ assert_equal 'Test', request.user_agent
8
+ end
9
+
10
+ it 'parses POST params when Content-Type is form-dataish' do
11
+ request = Sinatra::Request.new(
12
+ 'REQUEST_METHOD' => 'PUT',
13
+ 'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
14
+ 'rack.input' => StringIO.new('foo=bar')
15
+ )
16
+ assert_equal 'bar', request.params['foo']
17
+ end
18
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ require File.dirname(__FILE__) + '/helper'
4
+
5
+ describe 'Sinatra::Response' do
6
+ before do
7
+ @response = Sinatra::Response.new
8
+ end
9
+
10
+ it "initializes with 200, text/html, and empty body" do
11
+ assert_equal 200, @response.status
12
+ assert_equal 'text/html', @response['Content-Type']
13
+ assert_equal [], @response.body
14
+ end
15
+
16
+ it 'uses case insensitive headers' do
17
+ @response['content-type'] = 'application/foo'
18
+ assert_equal 'application/foo', @response['Content-Type']
19
+ assert_equal 'application/foo', @response['CONTENT-TYPE']
20
+ end
21
+
22
+ it 'writes to body' do
23
+ @response.body = 'Hello'
24
+ @response.write ' World'
25
+ assert_equal 'Hello World', @response.body
26
+ end
27
+
28
+ [204, 304].each do |status_code|
29
+ it "removes the Content-Type header and body when response status is #{status_code}" do
30
+ @response.status = status_code
31
+ @response.body = ['Hello World']
32
+ assert_equal [status_code, {}, []], @response.finish
33
+ end
34
+ end
35
+
36
+ it 'Calculates the Content-Length using the bytesize of the body' do
37
+ @response.body = ['Hello', 'World!', '✈']
38
+ status, headers, body = @response.finish
39
+ assert_equal '14', headers['Content-Length']
40
+ assert_equal @response.body, body
41
+ end
42
+ end
@@ -0,0 +1,98 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ describe 'Result Handling' do
4
+ it "sets response.body when result is a String" do
5
+ mock_app {
6
+ get '/' do
7
+ 'Hello World'
8
+ end
9
+ }
10
+
11
+ get '/'
12
+ assert ok?
13
+ assert_equal 'Hello World', body
14
+ end
15
+
16
+ it "sets response.body when result is an Array of Strings" do
17
+ mock_app {
18
+ get '/' do
19
+ ['Hello', 'World']
20
+ end
21
+ }
22
+
23
+ get '/'
24
+ assert ok?
25
+ assert_equal 'HelloWorld', body
26
+ end
27
+
28
+ it "sets response.body when result responds to #each" do
29
+ mock_app {
30
+ get '/' do
31
+ res = lambda { 'Hello World' }
32
+ def res.each ; yield call ; end
33
+ res
34
+ end
35
+ }
36
+
37
+ get '/'
38
+ assert ok?
39
+ assert_equal 'Hello World', body
40
+ end
41
+
42
+ it "sets response.body to [] when result is nil" do
43
+ mock_app {
44
+ get '/' do
45
+ nil
46
+ end
47
+ }
48
+
49
+ get '/'
50
+ assert ok?
51
+ assert_equal '', body
52
+ end
53
+
54
+ it "sets status, headers, and body when result is a Rack response tuple" do
55
+ mock_app {
56
+ get '/' do
57
+ [205, {'Content-Type' => 'foo/bar'}, 'Hello World']
58
+ end
59
+ }
60
+
61
+ get '/'
62
+ assert_equal 205, status
63
+ assert_equal 'foo/bar', response['Content-Type']
64
+ assert_equal 'Hello World', body
65
+ end
66
+
67
+ it "sets status and body when result is a two-tuple" do
68
+ mock_app {
69
+ get '/' do
70
+ [409, 'formula of']
71
+ end
72
+ }
73
+
74
+ get '/'
75
+ assert_equal 409, status
76
+ assert_equal 'formula of', body
77
+ end
78
+
79
+ it "raises a TypeError when result is a non two or three tuple Array" do
80
+ mock_app {
81
+ get '/' do
82
+ [409, 'formula of', 'something else', 'even more']
83
+ end
84
+ }
85
+
86
+ assert_raise(TypeError) { get '/' }
87
+ end
88
+
89
+ it "sets status when result is a Fixnum status code" do
90
+ mock_app {
91
+ get('/') { 205 }
92
+ }
93
+
94
+ get '/'
95
+ assert_equal 205, status
96
+ assert_equal '', body
97
+ end
98
+ end
@@ -0,0 +1,712 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ # Helper method for easy route pattern matching testing
4
+ def route_def(pattern)
5
+ mock_app { get(pattern) { } }
6
+ end
7
+
8
+ describe "Routing" do
9
+ %w[get put post delete].each do |verb|
10
+ it "defines #{verb.upcase} request handlers with #{verb}" do
11
+ mock_app {
12
+ send verb, '/hello' do
13
+ 'Hello World'
14
+ end
15
+ }
16
+
17
+ request = Rack::MockRequest.new(@app)
18
+ response = request.request(verb.upcase, '/hello', {})
19
+ assert response.ok?
20
+ assert_equal 'Hello World', response.body
21
+ end
22
+ end
23
+
24
+ it "defines HEAD request handlers with HEAD" do
25
+ mock_app {
26
+ head '/hello' do
27
+ response['X-Hello'] = 'World!'
28
+ 'remove me'
29
+ end
30
+ }
31
+
32
+ request = Rack::MockRequest.new(@app)
33
+ response = request.request('HEAD', '/hello', {})
34
+ assert response.ok?
35
+ assert_equal 'World!', response['X-Hello']
36
+ assert_equal '', response.body
37
+ end
38
+
39
+ it "404s when no route satisfies the request" do
40
+ mock_app {
41
+ get('/foo') { }
42
+ }
43
+ get '/bar'
44
+ assert_equal 404, status
45
+ end
46
+
47
+ it 'takes multiple definitions of a route' do
48
+ mock_app {
49
+ user_agent(/Foo/)
50
+ get '/foo' do
51
+ 'foo'
52
+ end
53
+
54
+ get '/foo' do
55
+ 'not foo'
56
+ end
57
+ }
58
+
59
+ get '/foo', {}, 'HTTP_USER_AGENT' => 'Foo'
60
+ assert ok?
61
+ assert_equal 'foo', body
62
+
63
+ get '/foo'
64
+ assert ok?
65
+ assert_equal 'not foo', body
66
+ end
67
+
68
+ it "exposes params with indifferent hash" do
69
+ mock_app {
70
+ get '/:foo' do
71
+ assert_equal 'bar', params['foo']
72
+ assert_equal 'bar', params[:foo]
73
+ 'well, alright'
74
+ end
75
+ }
76
+ get '/bar'
77
+ assert_equal 'well, alright', body
78
+ end
79
+
80
+ it "merges named params and query string params in params" do
81
+ mock_app {
82
+ get '/:foo' do
83
+ assert_equal 'bar', params['foo']
84
+ assert_equal 'biz', params['baz']
85
+ end
86
+ }
87
+ get '/bar?baz=biz'
88
+ assert ok?
89
+ end
90
+
91
+ it "supports named params like /hello/:person" do
92
+ mock_app {
93
+ get '/hello/:person' do
94
+ "Hello #{params['person']}"
95
+ end
96
+ }
97
+ get '/hello/Frank'
98
+ assert_equal 'Hello Frank', body
99
+ end
100
+
101
+ it "supports optional named params like /?:foo?/?:bar?" do
102
+ mock_app {
103
+ get '/?:foo?/?:bar?' do
104
+ "foo=#{params[:foo]};bar=#{params[:bar]}"
105
+ end
106
+ }
107
+
108
+ get '/hello/world'
109
+ assert ok?
110
+ assert_equal "foo=hello;bar=world", body
111
+
112
+ get '/hello'
113
+ assert ok?
114
+ assert_equal "foo=hello;bar=", body
115
+
116
+ get '/'
117
+ assert ok?
118
+ assert_equal "foo=;bar=", body
119
+ end
120
+
121
+ it "supports single splat params like /*" do
122
+ mock_app {
123
+ get '/*' do
124
+ assert params['splat'].kind_of?(Array)
125
+ params['splat'].join "\n"
126
+ end
127
+ }
128
+
129
+ get '/foo'
130
+ assert_equal "foo", body
131
+
132
+ get '/foo/bar/baz'
133
+ assert_equal "foo/bar/baz", body
134
+ end
135
+
136
+ it "supports mixing multiple splat params like /*/foo/*/*" do
137
+ mock_app {
138
+ get '/*/foo/*/*' do
139
+ assert params['splat'].kind_of?(Array)
140
+ params['splat'].join "\n"
141
+ end
142
+ }
143
+
144
+ get '/bar/foo/bling/baz/boom'
145
+ assert_equal "bar\nbling\nbaz/boom", body
146
+
147
+ get '/bar/foo/baz'
148
+ assert not_found?
149
+ end
150
+
151
+ it "supports mixing named and splat params like /:foo/*" do
152
+ mock_app {
153
+ get '/:foo/*' do
154
+ assert_equal 'foo', params['foo']
155
+ assert_equal ['bar/baz'], params['splat']
156
+ end
157
+ }
158
+
159
+ get '/foo/bar/baz'
160
+ assert ok?
161
+ end
162
+
163
+ it "matches a dot ('.') as part of a named param" do
164
+ mock_app {
165
+ get '/:foo/:bar' do
166
+ params[:foo]
167
+ end
168
+ }
169
+
170
+ get '/user@example.com/name'
171
+ assert_equal 200, response.status
172
+ assert_equal 'user@example.com', body
173
+ end
174
+
175
+ it "matches a literal dot ('.') outside of named params" do
176
+ mock_app {
177
+ get '/:file.:ext' do
178
+ assert_equal 'pony', params[:file]
179
+ assert_equal 'jpg', params[:ext]
180
+ 'right on'
181
+ end
182
+ }
183
+
184
+ get '/pony.jpg'
185
+ assert_equal 200, response.status
186
+ assert_equal 'right on', body
187
+ end
188
+
189
+ it "literally matches . in paths" do
190
+ route_def '/test.bar'
191
+
192
+ get '/test.bar'
193
+ assert ok?
194
+ get 'test0bar'
195
+ assert not_found?
196
+ end
197
+
198
+ it "literally matches $ in paths" do
199
+ route_def '/test$/'
200
+
201
+ get '/test$/'
202
+ assert ok?
203
+ end
204
+
205
+ it "literally matches + in paths" do
206
+ route_def '/te+st/'
207
+
208
+ get '/te%2Bst/'
209
+ assert ok?
210
+ get '/teeeeeeest/'
211
+ assert not_found?
212
+ end
213
+
214
+ it "literally matches () in paths" do
215
+ route_def '/test(bar)/'
216
+
217
+ get '/test(bar)/'
218
+ assert ok?
219
+ end
220
+
221
+ it "supports basic nested params" do
222
+ mock_app {
223
+ get '/hi' do
224
+ params["person"]["name"]
225
+ end
226
+ }
227
+
228
+ get "/hi?person[name]=John+Doe"
229
+ assert ok?
230
+ assert_equal "John Doe", body
231
+ end
232
+
233
+ it "exposes nested params with indifferent hash" do
234
+ mock_app {
235
+ get '/testme' do
236
+ assert_equal 'baz', params['bar']['foo']
237
+ assert_equal 'baz', params['bar'][:foo]
238
+ 'well, alright'
239
+ end
240
+ }
241
+ get '/testme?bar[foo]=baz'
242
+ assert_equal 'well, alright', body
243
+ end
244
+
245
+ it "supports deeply nested params" do
246
+ input = {
247
+ 'browser[chrome][engine][name]' => 'V8',
248
+ 'browser[chrome][engine][version]' => '1.0',
249
+ 'browser[firefox][engine][name]' => 'spidermonkey',
250
+ 'browser[firefox][engine][version]' => '1.7.0',
251
+ 'emacs[map][goto-line]' => 'M-g g',
252
+ 'emacs[version]' => '22.3.1',
253
+ 'paste[name]' => 'hello world',
254
+ 'paste[syntax]' => 'ruby'
255
+ }
256
+ expected = {
257
+ "emacs" => {
258
+ "map" => { "goto-line" => "M-g g" },
259
+ "version" => "22.3.1"
260
+ },
261
+ "browser" => {
262
+ "firefox" => {"engine" => {"name"=>"spidermonkey", "version"=>"1.7.0"}},
263
+ "chrome" => {"engine" => {"name"=>"V8", "version"=>"1.0"}}
264
+ },
265
+ "paste" => {"name"=>"hello world", "syntax"=>"ruby"}
266
+ }
267
+ mock_app {
268
+ get '/foo' do
269
+ assert_equal expected, params
270
+ 'looks good'
271
+ end
272
+ }
273
+ get "/foo?#{build_query(input)}"
274
+ assert ok?
275
+ assert_equal 'looks good', body
276
+ end
277
+
278
+ it "preserves non-nested params" do
279
+ mock_app {
280
+ get '/foo' do
281
+ assert_equal "2", params["article_id"]
282
+ assert_equal "awesome", params['comment']['body']
283
+ assert_nil params['comment[body]']
284
+ 'looks good'
285
+ end
286
+ }
287
+
288
+ get '/foo?article_id=2&comment[body]=awesome'
289
+ assert ok?
290
+ assert_equal 'looks good', body
291
+ end
292
+
293
+ it "matches paths that include spaces encoded with %20" do
294
+ mock_app {
295
+ get '/path with spaces' do
296
+ 'looks good'
297
+ end
298
+ }
299
+
300
+ get '/path%20with%20spaces'
301
+ assert ok?
302
+ assert_equal 'looks good', body
303
+ end
304
+
305
+ it "matches paths that include spaces encoded with +" do
306
+ mock_app {
307
+ get '/path with spaces' do
308
+ 'looks good'
309
+ end
310
+ }
311
+
312
+ get '/path+with+spaces'
313
+ assert ok?
314
+ assert_equal 'looks good', body
315
+ end
316
+
317
+ it "URL decodes named parameters and splats" do
318
+ mock_app {
319
+ get '/:foo/*' do
320
+ assert_equal 'hello world', params['foo']
321
+ assert_equal ['how are you'], params['splat']
322
+ nil
323
+ end
324
+ }
325
+
326
+ get '/hello%20world/how%20are%20you'
327
+ assert ok?
328
+ end
329
+
330
+ it 'supports regular expressions' do
331
+ mock_app {
332
+ get(/^\/foo...\/bar$/) do
333
+ 'Hello World'
334
+ end
335
+ }
336
+
337
+ get '/foooom/bar'
338
+ assert ok?
339
+ assert_equal 'Hello World', body
340
+ end
341
+
342
+ it 'makes regular expression captures available in params[:captures]' do
343
+ mock_app {
344
+ get(/^\/fo(.*)\/ba(.*)/) do
345
+ assert_equal ['orooomma', 'f'], params[:captures]
346
+ 'right on'
347
+ end
348
+ }
349
+
350
+ get '/foorooomma/baf'
351
+ assert ok?
352
+ assert_equal 'right on', body
353
+ end
354
+
355
+ it 'raises a TypeError when pattern is not a String or Regexp' do
356
+ @app = mock_app
357
+ assert_raise(TypeError) { @app.get(42){} }
358
+ end
359
+
360
+ it "returns response immediately on halt" do
361
+ mock_app {
362
+ get '/' do
363
+ halt 'Hello World'
364
+ 'Boo-hoo World'
365
+ end
366
+ }
367
+
368
+ get '/'
369
+ assert ok?
370
+ assert_equal 'Hello World', body
371
+ end
372
+
373
+ it "halts with a response tuple" do
374
+ mock_app {
375
+ get '/' do
376
+ halt 295, {'Content-Type' => 'text/plain'}, 'Hello World'
377
+ end
378
+ }
379
+
380
+ get '/'
381
+ assert_equal 295, status
382
+ assert_equal 'text/plain', response['Content-Type']
383
+ assert_equal 'Hello World', body
384
+ end
385
+
386
+ it "halts with an array of strings" do
387
+ mock_app {
388
+ get '/' do
389
+ halt %w[Hello World How Are You]
390
+ end
391
+ }
392
+
393
+ get '/'
394
+ assert_equal 'HelloWorldHowAreYou', body
395
+ end
396
+
397
+ it "transitions to the next matching route on pass" do
398
+ mock_app {
399
+ get '/:foo' do
400
+ pass
401
+ 'Hello Foo'
402
+ end
403
+
404
+ get '/*' do
405
+ assert !params.include?('foo')
406
+ 'Hello World'
407
+ end
408
+ }
409
+
410
+ get '/bar'
411
+ assert ok?
412
+ assert_equal 'Hello World', body
413
+ end
414
+
415
+ it "transitions to 404 when passed and no subsequent route matches" do
416
+ mock_app {
417
+ get '/:foo' do
418
+ pass
419
+ 'Hello Foo'
420
+ end
421
+ }
422
+
423
+ get '/bar'
424
+ assert not_found?
425
+ end
426
+
427
+ it "passes when matching condition returns false" do
428
+ mock_app {
429
+ condition { params[:foo] == 'bar' }
430
+ get '/:foo' do
431
+ 'Hello World'
432
+ end
433
+ }
434
+
435
+ get '/bar'
436
+ assert ok?
437
+ assert_equal 'Hello World', body
438
+
439
+ get '/foo'
440
+ assert not_found?
441
+ end
442
+
443
+ it "does not pass when matching condition returns nil" do
444
+ mock_app {
445
+ condition { nil }
446
+ get '/:foo' do
447
+ 'Hello World'
448
+ end
449
+ }
450
+
451
+ get '/bar'
452
+ assert ok?
453
+ assert_equal 'Hello World', body
454
+ end
455
+
456
+ it "passes to next route when condition calls pass explicitly" do
457
+ mock_app {
458
+ condition { pass unless params[:foo] == 'bar' }
459
+ get '/:foo' do
460
+ 'Hello World'
461
+ end
462
+ }
463
+
464
+ get '/bar'
465
+ assert ok?
466
+ assert_equal 'Hello World', body
467
+
468
+ get '/foo'
469
+ assert not_found?
470
+ end
471
+
472
+ it "passes to the next route when host_name does not match" do
473
+ mock_app {
474
+ host_name 'example.com'
475
+ get '/foo' do
476
+ 'Hello World'
477
+ end
478
+ }
479
+ get '/foo'
480
+ assert not_found?
481
+
482
+ get '/foo', :env => { 'HTTP_HOST' => 'example.com' }
483
+ assert_equal 200, status
484
+ assert_equal 'Hello World', body
485
+ end
486
+
487
+ it "passes to the next route when user_agent does not match" do
488
+ mock_app {
489
+ user_agent(/Foo/)
490
+ get '/foo' do
491
+ 'Hello World'
492
+ end
493
+ }
494
+ get '/foo'
495
+ assert not_found?
496
+
497
+ get '/foo', :env => { 'HTTP_USER_AGENT' => 'Foo Bar' }
498
+ assert_equal 200, status
499
+ assert_equal 'Hello World', body
500
+ end
501
+
502
+ it "makes captures in user agent pattern available in params[:agent]" do
503
+ mock_app {
504
+ user_agent(/Foo (.*)/)
505
+ get '/foo' do
506
+ 'Hello ' + params[:agent].first
507
+ end
508
+ }
509
+ get '/foo', :env => { 'HTTP_USER_AGENT' => 'Foo Bar' }
510
+ assert_equal 200, status
511
+ assert_equal 'Hello Bar', body
512
+ end
513
+
514
+ it "filters by accept header" do
515
+ mock_app {
516
+ get '/', :provides => :xml do
517
+ request.env['HTTP_ACCEPT']
518
+ end
519
+ }
520
+
521
+ get '/', :env => { :accept => 'application/xml' }
522
+ assert ok?
523
+ assert_equal 'application/xml', body
524
+ assert_equal 'application/xml', response.headers['Content-Type']
525
+
526
+ get '/', :env => { :accept => 'text/html' }
527
+ assert !ok?
528
+ end
529
+
530
+ it "allows multiple mime types for accept header" do
531
+ types = ['image/jpeg', 'image/pjpeg']
532
+
533
+ mock_app {
534
+ get '/', :provides => types do
535
+ request.env['HTTP_ACCEPT']
536
+ end
537
+ }
538
+
539
+ types.each do |type|
540
+ get '/', :env => { :accept => type }
541
+ assert ok?
542
+ assert_equal type, body
543
+ assert_equal type, response.headers['Content-Type']
544
+ end
545
+ end
546
+
547
+ it 'degrades gracefully when optional accept header is not provided' do
548
+ mock_app {
549
+ get '/', :provides => :xml do
550
+ request.env['HTTP_ACCEPT']
551
+ end
552
+ get '/' do
553
+ 'default'
554
+ end
555
+ }
556
+ get '/'
557
+ assert ok?
558
+ assert_equal 'default', body
559
+ end
560
+
561
+ it 'passes a single url param as block parameters when one param is specified' do
562
+ mock_app {
563
+ get '/:foo' do |foo|
564
+ assert_equal 'bar', foo
565
+ end
566
+ }
567
+
568
+ get '/bar'
569
+ assert ok?
570
+ end
571
+
572
+ it 'passes multiple params as block parameters when many are specified' do
573
+ mock_app {
574
+ get '/:foo/:bar/:baz' do |foo, bar, baz|
575
+ assert_equal 'abc', foo
576
+ assert_equal 'def', bar
577
+ assert_equal 'ghi', baz
578
+ end
579
+ }
580
+
581
+ get '/abc/def/ghi'
582
+ assert ok?
583
+ end
584
+
585
+ it 'passes regular expression captures as block parameters' do
586
+ mock_app {
587
+ get(/^\/fo(.*)\/ba(.*)/) do |foo, bar|
588
+ assert_equal 'orooomma', foo
589
+ assert_equal 'f', bar
590
+ 'looks good'
591
+ end
592
+ }
593
+
594
+ get '/foorooomma/baf'
595
+ assert ok?
596
+ assert_equal 'looks good', body
597
+ end
598
+
599
+ it "supports mixing multiple splat params like /*/foo/*/* as block parameters" do
600
+ mock_app {
601
+ get '/*/foo/*/*' do |foo, bar, baz|
602
+ assert_equal 'bar', foo
603
+ assert_equal 'bling', bar
604
+ assert_equal 'baz/boom', baz
605
+ 'looks good'
606
+ end
607
+ }
608
+
609
+ get '/bar/foo/bling/baz/boom'
610
+ assert ok?
611
+ assert_equal 'looks good', body
612
+ end
613
+
614
+ it 'raises an ArgumentError with block arity > 1 and too many values' do
615
+ mock_app {
616
+ get '/:foo/:bar/:baz' do |foo, bar|
617
+ 'quux'
618
+ end
619
+ }
620
+
621
+ assert_raise(ArgumentError) { get '/a/b/c' }
622
+ end
623
+
624
+ it 'raises an ArgumentError with block param arity > 1 and too few values' do
625
+ mock_app {
626
+ get '/:foo/:bar' do |foo, bar, baz|
627
+ 'quux'
628
+ end
629
+ }
630
+
631
+ assert_raise(ArgumentError) { get '/a/b' }
632
+ end
633
+
634
+ it 'succeeds if no block parameters are specified' do
635
+ mock_app {
636
+ get '/:foo/:bar' do
637
+ 'quux'
638
+ end
639
+ }
640
+
641
+ get '/a/b'
642
+ assert ok?
643
+ assert_equal 'quux', body
644
+ end
645
+
646
+ it 'passes all params with block param arity -1 (splat args)' do
647
+ mock_app {
648
+ get '/:foo/:bar' do |*args|
649
+ args.join
650
+ end
651
+ }
652
+
653
+ get '/a/b'
654
+ assert ok?
655
+ assert_equal 'ab', body
656
+ end
657
+
658
+ # NOTE Block params behaves differently under 1.8 and 1.9. Under 1.8, block
659
+ # param arity is lax: declaring a mismatched number of block params results
660
+ # in a warning. Under 1.9, block param arity is strict: mismatched block
661
+ # arity raises an ArgumentError.
662
+
663
+ if RUBY_VERSION >= '1.9'
664
+
665
+ it 'raises an ArgumentError with block param arity 1 and no values' do
666
+ mock_app {
667
+ get '/foo' do |foo|
668
+ 'quux'
669
+ end
670
+ }
671
+
672
+ assert_raise(ArgumentError) { get '/foo' }
673
+ end
674
+
675
+ it 'raises an ArgumentError with block param arity 1 and too many values' do
676
+ mock_app {
677
+ get '/:foo/:bar/:baz' do |foo|
678
+ 'quux'
679
+ end
680
+ }
681
+
682
+ assert_raise(ArgumentError) { get '/a/b/c' }
683
+ end
684
+
685
+ else
686
+
687
+ it 'does not raise an ArgumentError with block param arity 1 and no values' do
688
+ mock_app {
689
+ get '/foo' do |foo|
690
+ 'quux'
691
+ end
692
+ }
693
+
694
+ silence_warnings { get '/foo' }
695
+ assert ok?
696
+ assert_equal 'quux', body
697
+ end
698
+
699
+ it 'does not raise an ArgumentError with block param arity 1 and too many values' do
700
+ mock_app {
701
+ get '/:foo/:bar/:baz' do |foo|
702
+ 'quux'
703
+ end
704
+ }
705
+
706
+ silence_warnings { get '/a/b/c' }
707
+ assert ok?
708
+ assert_equal 'quux', body
709
+ end
710
+
711
+ end
712
+ end