sinatra 1.4.6 → 2.0.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.

Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS.md +5 -2
  3. data/{CHANGES → CHANGELOG.md} +126 -46
  4. data/CONTRIBUTING.md +100 -0
  5. data/Gemfile +12 -17
  6. data/LICENSE +5 -2
  7. data/MAINTENANCE.md +42 -0
  8. data/README.de.md +711 -466
  9. data/README.es.md +206 -171
  10. data/README.fr.md +370 -344
  11. data/README.hu.md +44 -10
  12. data/README.ja.md +300 -210
  13. data/README.ko.md +230 -191
  14. data/README.md +675 -528
  15. data/README.pt-br.md +149 -115
  16. data/README.pt-pt.md +65 -65
  17. data/README.ru.md +198 -97
  18. data/README.zh.md +1943 -1237
  19. data/Rakefile +72 -49
  20. data/SECURITY.md +35 -0
  21. data/lib/sinatra/base.rb +141 -207
  22. data/lib/sinatra/indifferent_hash.rb +150 -0
  23. data/lib/sinatra/main.rb +1 -0
  24. data/lib/sinatra/show_exceptions.rb +70 -56
  25. data/lib/sinatra/version.rb +1 -1
  26. data/sinatra.gemspec +19 -7
  27. metadata +32 -163
  28. data/test/asciidoctor_test.rb +0 -72
  29. data/test/base_test.rb +0 -167
  30. data/test/builder_test.rb +0 -91
  31. data/test/coffee_test.rb +0 -96
  32. data/test/compile_test.rb +0 -183
  33. data/test/contest.rb +0 -91
  34. data/test/creole_test.rb +0 -65
  35. data/test/delegator_test.rb +0 -160
  36. data/test/encoding_test.rb +0 -20
  37. data/test/erb_test.rb +0 -116
  38. data/test/extensions_test.rb +0 -98
  39. data/test/filter_test.rb +0 -487
  40. data/test/haml_test.rb +0 -109
  41. data/test/helper.rb +0 -132
  42. data/test/helpers_test.rb +0 -1917
  43. data/test/integration/app.rb +0 -79
  44. data/test/integration_helper.rb +0 -236
  45. data/test/integration_test.rb +0 -104
  46. data/test/less_test.rb +0 -69
  47. data/test/liquid_test.rb +0 -77
  48. data/test/mapped_error_test.rb +0 -285
  49. data/test/markaby_test.rb +0 -80
  50. data/test/markdown_test.rb +0 -85
  51. data/test/mediawiki_test.rb +0 -68
  52. data/test/middleware_test.rb +0 -68
  53. data/test/nokogiri_test.rb +0 -67
  54. data/test/public/favicon.ico +0 -0
  55. data/test/rabl_test.rb +0 -89
  56. data/test/rack_test.rb +0 -45
  57. data/test/radius_test.rb +0 -59
  58. data/test/rdoc_test.rb +0 -66
  59. data/test/readme_test.rb +0 -130
  60. data/test/request_test.rb +0 -100
  61. data/test/response_test.rb +0 -63
  62. data/test/result_test.rb +0 -76
  63. data/test/route_added_hook_test.rb +0 -59
  64. data/test/routing_test.rb +0 -1412
  65. data/test/sass_test.rb +0 -115
  66. data/test/scss_test.rb +0 -88
  67. data/test/server_test.rb +0 -56
  68. data/test/settings_test.rb +0 -582
  69. data/test/sinatra_test.rb +0 -12
  70. data/test/slim_test.rb +0 -102
  71. data/test/static_test.rb +0 -236
  72. data/test/streaming_test.rb +0 -149
  73. data/test/stylus_test.rb +0 -90
  74. data/test/templates_test.rb +0 -382
  75. data/test/textile_test.rb +0 -65
  76. data/test/views/a/in_a.str +0 -1
  77. data/test/views/ascii.erb +0 -2
  78. data/test/views/b/in_b.str +0 -1
  79. data/test/views/calc.html.erb +0 -1
  80. data/test/views/error.builder +0 -3
  81. data/test/views/error.erb +0 -3
  82. data/test/views/error.haml +0 -3
  83. data/test/views/error.sass +0 -2
  84. data/test/views/explicitly_nested.str +0 -1
  85. data/test/views/foo/hello.test +0 -1
  86. data/test/views/hello.asciidoc +0 -1
  87. data/test/views/hello.builder +0 -1
  88. data/test/views/hello.coffee +0 -1
  89. data/test/views/hello.creole +0 -1
  90. data/test/views/hello.erb +0 -1
  91. data/test/views/hello.haml +0 -1
  92. data/test/views/hello.less +0 -5
  93. data/test/views/hello.liquid +0 -1
  94. data/test/views/hello.mab +0 -1
  95. data/test/views/hello.md +0 -1
  96. data/test/views/hello.mediawiki +0 -1
  97. data/test/views/hello.nokogiri +0 -1
  98. data/test/views/hello.rabl +0 -2
  99. data/test/views/hello.radius +0 -1
  100. data/test/views/hello.rdoc +0 -1
  101. data/test/views/hello.sass +0 -2
  102. data/test/views/hello.scss +0 -3
  103. data/test/views/hello.slim +0 -1
  104. data/test/views/hello.str +0 -1
  105. data/test/views/hello.styl +0 -2
  106. data/test/views/hello.test +0 -1
  107. data/test/views/hello.textile +0 -1
  108. data/test/views/hello.wlang +0 -1
  109. data/test/views/hello.yajl +0 -1
  110. data/test/views/layout2.builder +0 -3
  111. data/test/views/layout2.erb +0 -2
  112. data/test/views/layout2.haml +0 -2
  113. data/test/views/layout2.liquid +0 -2
  114. data/test/views/layout2.mab +0 -2
  115. data/test/views/layout2.nokogiri +0 -3
  116. data/test/views/layout2.rabl +0 -3
  117. data/test/views/layout2.radius +0 -2
  118. data/test/views/layout2.slim +0 -3
  119. data/test/views/layout2.str +0 -2
  120. data/test/views/layout2.test +0 -1
  121. data/test/views/layout2.wlang +0 -2
  122. data/test/views/nested.str +0 -1
  123. data/test/views/utf8.erb +0 -2
  124. data/test/wlang_test.rb +0 -87
  125. data/test/yajl_test.rb +0 -86
data/test/routing_test.rb DELETED
@@ -1,1412 +0,0 @@
1
- # I like coding: UTF-8
2
- require File.expand_path('../helper', __FILE__)
3
-
4
- # Helper method for easy route pattern matching testing
5
- def route_def(pattern)
6
- mock_app { get(pattern) { } }
7
- end
8
-
9
- class RegexpLookAlike
10
- class MatchData
11
- def captures
12
- ["this", "is", "a", "test"]
13
- end
14
- end
15
-
16
- def match(string)
17
- ::RegexpLookAlike::MatchData.new if string == "/this/is/a/test/"
18
- end
19
-
20
- def keys
21
- ["one", "two", "three", "four"]
22
- end
23
- end
24
-
25
- class RoutingTest < Minitest::Test
26
- %w[get put post delete options patch link unlink].each do |verb|
27
- it "defines #{verb.upcase} request handlers with #{verb}" do
28
- mock_app {
29
- send verb, '/hello' do
30
- 'Hello World'
31
- end
32
- }
33
-
34
- request = Rack::MockRequest.new(@app)
35
- response = request.request(verb.upcase, '/hello', {})
36
- assert response.ok?
37
- assert_equal 'Hello World', response.body
38
- end
39
- end
40
-
41
- it "defines HEAD request handlers with HEAD" do
42
- mock_app {
43
- head '/hello' do
44
- response['X-Hello'] = 'World!'
45
- 'remove me'
46
- end
47
- }
48
-
49
- request = Rack::MockRequest.new(@app)
50
- response = request.request('HEAD', '/hello', {})
51
- assert response.ok?
52
- assert_equal 'World!', response['X-Hello']
53
- assert_equal '', response.body
54
- end
55
-
56
- it "404s when no route satisfies the request" do
57
- mock_app {
58
- get('/foo') { }
59
- }
60
- get '/bar'
61
- assert_equal 404, status
62
- end
63
-
64
- it "404s and sets X-Cascade header when no route satisfies the request" do
65
- mock_app {
66
- get('/foo') { }
67
- }
68
- get '/bar'
69
- assert_equal 404, status
70
- assert_equal 'pass', response.headers['X-Cascade']
71
- end
72
-
73
- it "404s and does not set X-Cascade header when no route satisfies the request and x_cascade has been disabled" do
74
- mock_app {
75
- disable :x_cascade
76
- get('/foo') { }
77
- }
78
- get '/bar'
79
- assert_equal 404, status
80
- assert_equal nil, response.headers['X-Cascade']
81
- end
82
-
83
-
84
- it "allows using unicode" do
85
- mock_app do
86
- get('/föö') { }
87
- end
88
- get '/f%C3%B6%C3%B6'
89
- assert_equal 200, status
90
- end
91
-
92
- it "it handles encoded slashes correctly" do
93
- mock_app {
94
- set :protection, :except => :path_traversal
95
- get("/:a") { |a| a }
96
- }
97
- get '/foo%2Fbar'
98
- assert_equal 200, status
99
- assert_body "foo/bar"
100
- end
101
-
102
- it "overrides the content-type in error handlers" do
103
- mock_app {
104
- before { content_type 'text/plain' }
105
- error Sinatra::NotFound do
106
- content_type "text/html"
107
- "<h1>Not Found</h1>"
108
- end
109
- }
110
-
111
- get '/foo'
112
- assert_equal 404, status
113
- assert_equal 'text/html;charset=utf-8', response["Content-Type"]
114
- assert_equal "<h1>Not Found</h1>", response.body
115
- end
116
-
117
- it "recalculates body length correctly for 404 response" do
118
- mock_app {
119
- get '/' do
120
- @response["Content-Length"] = "30"
121
- raise Sinatra::NotFound
122
- end
123
- }
124
-
125
- get "/"
126
- assert_equal "18", response["Content-Length"]
127
- assert_equal 404, status
128
- end
129
-
130
- it 'matches empty PATH_INFO to "/" if no route is defined for ""' do
131
- mock_app do
132
- get '/' do
133
- 'worked'
134
- end
135
- end
136
-
137
- get '/', {}, "PATH_INFO" => ""
138
- assert ok?
139
- assert_equal 'worked', body
140
- end
141
-
142
- it 'matches empty PATH_INFO to "" if a route is defined for ""' do
143
- mock_app do
144
- disable :protection
145
-
146
- get '/' do
147
- 'did not work'
148
- end
149
-
150
- get '' do
151
- 'worked'
152
- end
153
- end
154
-
155
- get '/', {}, "PATH_INFO" => ""
156
- assert ok?
157
- assert_equal 'worked', body
158
- end
159
-
160
- it 'takes multiple definitions of a route' do
161
- mock_app {
162
- user_agent(/Foo/)
163
- get '/foo' do
164
- 'foo'
165
- end
166
-
167
- get '/foo' do
168
- 'not foo'
169
- end
170
- }
171
-
172
- get '/foo', {}, 'HTTP_USER_AGENT' => 'Foo'
173
- assert ok?
174
- assert_equal 'foo', body
175
-
176
- get '/foo'
177
- assert ok?
178
- assert_equal 'not foo', body
179
- end
180
-
181
- it "exposes params with indifferent hash" do
182
- mock_app {
183
- get '/:foo' do
184
- assert_equal 'bar', params['foo']
185
- assert_equal 'bar', params[:foo]
186
- 'well, alright'
187
- end
188
- }
189
- get '/bar'
190
- assert_equal 'well, alright', body
191
- end
192
-
193
- it "merges named params and query string params in params" do
194
- mock_app {
195
- get '/:foo' do
196
- assert_equal 'bar', params['foo']
197
- assert_equal 'biz', params['baz']
198
- end
199
- }
200
- get '/bar?baz=biz'
201
- assert ok?
202
- end
203
-
204
- it "supports named params like /hello/:person" do
205
- mock_app {
206
- get '/hello/:person' do
207
- "Hello #{params['person']}"
208
- end
209
- }
210
- get '/hello/Frank'
211
- assert_equal 'Hello Frank', body
212
- end
213
-
214
- it "supports optional named params like /?:foo?/?:bar?" do
215
- mock_app {
216
- get '/?:foo?/?:bar?' do
217
- "foo=#{params[:foo]};bar=#{params[:bar]}"
218
- end
219
- }
220
-
221
- get '/hello/world'
222
- assert ok?
223
- assert_equal "foo=hello;bar=world", body
224
-
225
- get '/hello'
226
- assert ok?
227
- assert_equal "foo=hello;bar=", body
228
-
229
- get '/'
230
- assert ok?
231
- assert_equal "foo=;bar=", body
232
- end
233
-
234
- it "supports named captures like %r{/hello/(?<person>[^/?#]+)} on Ruby >= 1.9" do
235
- next if RUBY_VERSION < '1.9'
236
- mock_app {
237
- get Regexp.new('/hello/(?<person>[^/?#]+)') do
238
- "Hello #{params['person']}"
239
- end
240
- }
241
- get '/hello/Frank'
242
- assert_equal 'Hello Frank', body
243
- end
244
-
245
- it "supports optional named captures like %r{/page(?<format>.[^/?#]+)?} on Ruby >= 1.9" do
246
- next if RUBY_VERSION < '1.9'
247
- mock_app {
248
- get Regexp.new('/page(?<format>.[^/?#]+)?') do
249
- "format=#{params[:format]}"
250
- end
251
- }
252
-
253
- get '/page.html'
254
- assert ok?
255
- assert_equal "format=.html", body
256
-
257
- get '/page.xml'
258
- assert ok?
259
- assert_equal "format=.xml", body
260
-
261
- get '/page'
262
- assert ok?
263
- assert_equal "format=", body
264
- end
265
-
266
- it 'does not concatenate params with the same name' do
267
- mock_app { get('/:foo') { params[:foo] } }
268
- get '/a?foo=b'
269
- assert_body 'a'
270
- end
271
-
272
- it "supports single splat params like /*" do
273
- mock_app {
274
- get '/*' do
275
- assert params['splat'].kind_of?(Array)
276
- params['splat'].join "\n"
277
- end
278
- }
279
-
280
- get '/foo'
281
- assert_equal "foo", body
282
-
283
- get '/foo/bar/baz'
284
- assert_equal "foo/bar/baz", body
285
- end
286
-
287
- it "supports mixing multiple splat params like /*/foo/*/*" do
288
- mock_app {
289
- get '/*/foo/*/*' do
290
- assert params['splat'].kind_of?(Array)
291
- params['splat'].join "\n"
292
- end
293
- }
294
-
295
- get '/bar/foo/bling/baz/boom'
296
- assert_equal "bar\nbling\nbaz/boom", body
297
-
298
- get '/bar/foo/baz'
299
- assert not_found?
300
- end
301
-
302
- it "supports mixing named and splat params like /:foo/*" do
303
- mock_app {
304
- get '/:foo/*' do
305
- assert_equal 'foo', params['foo']
306
- assert_equal ['bar/baz'], params['splat']
307
- end
308
- }
309
-
310
- get '/foo/bar/baz'
311
- assert ok?
312
- end
313
-
314
- it "matches a dot ('.') as part of a named param" do
315
- mock_app {
316
- get '/:foo/:bar' do
317
- params[:foo]
318
- end
319
- }
320
-
321
- get '/user@example.com/name'
322
- assert_equal 200, response.status
323
- assert_equal 'user@example.com', body
324
- end
325
-
326
- it "matches a literal dot ('.') outside of named params" do
327
- mock_app {
328
- get '/:file.:ext' do
329
- assert_equal 'pony', params[:file]
330
- assert_equal 'jpg', params[:ext]
331
- 'right on'
332
- end
333
- }
334
-
335
- get '/pony.jpg'
336
- assert_equal 200, response.status
337
- assert_equal 'right on', body
338
- end
339
-
340
- it "literally matches dot in paths" do
341
- route_def '/test.bar'
342
-
343
- get '/test.bar'
344
- assert ok?
345
- get 'test0bar'
346
- assert not_found?
347
- end
348
-
349
- it "literally matches dollar sign in paths" do
350
- route_def '/test$/'
351
-
352
- get '/test$/'
353
- assert ok?
354
- end
355
-
356
- it "literally matches plus sign in paths" do
357
- route_def '/te+st/'
358
-
359
- get '/te%2Bst/'
360
- assert ok?
361
- get '/teeeeeeest/'
362
- assert not_found?
363
- end
364
-
365
- it "does not convert plus sign into space as the value of a named param" do
366
- mock_app do
367
- get '/:test' do
368
- params["test"]
369
- end
370
- end
371
- get '/bob+ross'
372
- assert ok?
373
- assert_equal 'bob+ross', body
374
- end
375
-
376
- it "literally matches parens in paths" do
377
- route_def '/test(bar)/'
378
-
379
- get '/test(bar)/'
380
- assert ok?
381
- end
382
-
383
- it "supports basic nested params" do
384
- mock_app {
385
- get '/hi' do
386
- params["person"]["name"]
387
- end
388
- }
389
-
390
- get "/hi?person[name]=John+Doe"
391
- assert ok?
392
- assert_equal "John Doe", body
393
- end
394
-
395
- it "exposes nested params with indifferent hash" do
396
- mock_app {
397
- get '/testme' do
398
- assert_equal 'baz', params['bar']['foo']
399
- assert_equal 'baz', params['bar'][:foo]
400
- 'well, alright'
401
- end
402
- }
403
- get '/testme?bar[foo]=baz'
404
- assert_equal 'well, alright', body
405
- end
406
-
407
- it "exposes params nested within arrays with indifferent hash" do
408
- mock_app {
409
- get '/testme' do
410
- assert_equal 'baz', params['bar'][0]['foo']
411
- assert_equal 'baz', params['bar'][0][:foo]
412
- 'well, alright'
413
- end
414
- }
415
- get '/testme?bar[][foo]=baz'
416
- assert_equal 'well, alright', body
417
- end
418
-
419
- it "supports arrays within params" do
420
- mock_app {
421
- get '/foo' do
422
- assert_equal ['A', 'B'], params['bar']
423
- 'looks good'
424
- end
425
- }
426
- get '/foo?bar[]=A&bar[]=B'
427
- assert ok?
428
- assert_equal 'looks good', body
429
- end
430
-
431
- it "supports deeply nested params" do
432
- expected_params = {
433
- "emacs" => {
434
- "map" => { "goto-line" => "M-g g" },
435
- "version" => "22.3.1"
436
- },
437
- "browser" => {
438
- "firefox" => {"engine" => {"name"=>"spidermonkey", "version"=>"1.7.0"}},
439
- "chrome" => {"engine" => {"name"=>"V8", "version"=>"1.0"}}
440
- },
441
- "paste" => {"name"=>"hello world", "syntax"=>"ruby"}
442
- }
443
- mock_app {
444
- get '/foo' do
445
- assert_equal expected_params, params
446
- 'looks good'
447
- end
448
- }
449
- get '/foo', expected_params
450
- assert ok?
451
- assert_equal 'looks good', body
452
- end
453
-
454
- it "preserves non-nested params" do
455
- mock_app {
456
- get '/foo' do
457
- assert_equal "2", params["article_id"]
458
- assert_equal "awesome", params['comment']['body']
459
- assert_nil params['comment[body]']
460
- 'looks good'
461
- end
462
- }
463
-
464
- get '/foo?article_id=2&comment[body]=awesome'
465
- assert ok?
466
- assert_equal 'looks good', body
467
- end
468
-
469
- it "matches paths that include spaces encoded with %20" do
470
- mock_app {
471
- get '/path with spaces' do
472
- 'looks good'
473
- end
474
- }
475
-
476
- get '/path%20with%20spaces'
477
- assert ok?
478
- assert_equal 'looks good', body
479
- end
480
-
481
- it "matches paths that include spaces encoded with +" do
482
- mock_app {
483
- get '/path with spaces' do
484
- 'looks good'
485
- end
486
- }
487
-
488
- get '/path+with+spaces'
489
- assert ok?
490
- assert_equal 'looks good', body
491
- end
492
-
493
- it "matches paths that include ampersands" do
494
- mock_app {
495
- get '/:name' do
496
- 'looks good'
497
- end
498
- }
499
-
500
- get '/foo&bar'
501
- assert ok?
502
- assert_equal 'looks good', body
503
- end
504
-
505
- it "URL decodes named parameters and splats" do
506
- mock_app {
507
- get '/:foo/*' do
508
- assert_equal 'hello world', params['foo']
509
- assert_equal ['how are you'], params['splat']
510
- nil
511
- end
512
- }
513
-
514
- get '/hello%20world/how%20are%20you'
515
- assert ok?
516
- end
517
-
518
- it 'supports regular expressions' do
519
- mock_app {
520
- get(/^\/foo...\/bar$/) do
521
- 'Hello World'
522
- end
523
- }
524
-
525
- get '/foooom/bar'
526
- assert ok?
527
- assert_equal 'Hello World', body
528
- end
529
-
530
- it 'makes regular expression captures available in params[:captures]' do
531
- mock_app {
532
- get(/^\/fo(.*)\/ba(.*)/) do
533
- assert_equal ['orooomma', 'f'], params[:captures]
534
- 'right on'
535
- end
536
- }
537
-
538
- get '/foorooomma/baf'
539
- assert ok?
540
- assert_equal 'right on', body
541
- end
542
-
543
- it 'supports regular expression look-alike routes' do
544
- mock_app {
545
- get(RegexpLookAlike.new) do
546
- assert_equal 'this', params[:one]
547
- assert_equal 'is', params[:two]
548
- assert_equal 'a', params[:three]
549
- assert_equal 'test', params[:four]
550
- 'right on'
551
- end
552
- }
553
-
554
- get '/this/is/a/test/'
555
- assert ok?
556
- assert_equal 'right on', body
557
- end
558
-
559
- it 'raises a TypeError when pattern is not a String or Regexp' do
560
- assert_raises(TypeError) {
561
- mock_app { get(42){} }
562
- }
563
- end
564
-
565
- it "returns response immediately on halt" do
566
- mock_app {
567
- get '/' do
568
- halt 'Hello World'
569
- 'Boo-hoo World'
570
- end
571
- }
572
-
573
- get '/'
574
- assert ok?
575
- assert_equal 'Hello World', body
576
- end
577
-
578
- it "halts with a response tuple" do
579
- mock_app {
580
- get '/' do
581
- halt 295, {'Content-Type' => 'text/plain'}, 'Hello World'
582
- end
583
- }
584
-
585
- get '/'
586
- assert_equal 295, status
587
- assert_equal 'text/plain', response['Content-Type']
588
- assert_equal 'Hello World', body
589
- end
590
-
591
- it "halts with an array of strings" do
592
- mock_app {
593
- get '/' do
594
- halt %w[Hello World How Are You]
595
- end
596
- }
597
-
598
- get '/'
599
- assert_equal 'HelloWorldHowAreYou', body
600
- end
601
-
602
- it 'sets response.status with halt' do
603
- status_was = nil
604
- mock_app do
605
- after { status_was = status }
606
- get('/') { halt 500, 'error' }
607
- end
608
- get '/'
609
- assert_status 500
610
- assert_equal 500, status_was
611
- end
612
-
613
- it "transitions to the next matching route on pass" do
614
- mock_app {
615
- get '/:foo' do
616
- pass
617
- 'Hello Foo'
618
- end
619
-
620
- get '/*' do
621
- assert !params.include?('foo')
622
- 'Hello World'
623
- end
624
- }
625
-
626
- get '/bar'
627
- assert ok?
628
- assert_equal 'Hello World', body
629
- end
630
-
631
- it "transitions to 404 when passed and no subsequent route matches" do
632
- mock_app {
633
- get '/:foo' do
634
- pass
635
- 'Hello Foo'
636
- end
637
- }
638
-
639
- get '/bar'
640
- assert not_found?
641
- end
642
-
643
- it "transitions to 404 and sets X-Cascade header when passed and no subsequent route matches" do
644
- mock_app {
645
- get '/:foo' do
646
- pass
647
- 'Hello Foo'
648
- end
649
-
650
- get '/bar' do
651
- 'Hello Bar'
652
- end
653
- }
654
-
655
- get '/foo'
656
- assert not_found?
657
- assert_equal 'pass', response.headers['X-Cascade']
658
- end
659
-
660
- it "uses optional block passed to pass as route block if no other route is found" do
661
- mock_app {
662
- get "/" do
663
- pass do
664
- "this"
665
- end
666
- "not this"
667
- end
668
- }
669
-
670
- get "/"
671
- assert ok?
672
- assert "this", body
673
- end
674
-
675
- it "uses optional block passed to pass as route block if no other route is found and superclass has non-matching routes" do
676
- base = Class.new(Sinatra::Base)
677
- base.get('/foo') { 'foo in baseclass' }
678
-
679
- mock_app(base) {
680
- get "/" do
681
- pass do
682
- "this"
683
- end
684
- "not this"
685
- end
686
- }
687
-
688
- get "/"
689
- assert_equal 200, status
690
- assert "this", body
691
- end
692
-
693
- it "passes when matching condition returns false" do
694
- mock_app {
695
- condition { params[:foo] == 'bar' }
696
- get '/:foo' do
697
- 'Hello World'
698
- end
699
- }
700
-
701
- get '/bar'
702
- assert ok?
703
- assert_equal 'Hello World', body
704
-
705
- get '/foo'
706
- assert not_found?
707
- end
708
-
709
- it "does not pass when matching condition returns nil" do
710
- mock_app {
711
- condition { nil }
712
- get '/:foo' do
713
- 'Hello World'
714
- end
715
- }
716
-
717
- get '/bar'
718
- assert ok?
719
- assert_equal 'Hello World', body
720
- end
721
-
722
- it "passes to next route when condition calls pass explicitly" do
723
- mock_app {
724
- condition { pass unless params[:foo] == 'bar' }
725
- get '/:foo' do
726
- 'Hello World'
727
- end
728
- }
729
-
730
- get '/bar'
731
- assert ok?
732
- assert_equal 'Hello World', body
733
-
734
- get '/foo'
735
- assert not_found?
736
- end
737
-
738
- it "passes to the next route when host_name does not match" do
739
- mock_app {
740
- host_name 'example.com'
741
- get '/foo' do
742
- 'Hello World'
743
- end
744
- }
745
- get '/foo'
746
- assert not_found?
747
-
748
- get '/foo', {}, { 'HTTP_HOST' => 'example.com' }
749
- assert_equal 200, status
750
- assert_equal 'Hello World', body
751
- end
752
-
753
- it "passes to the next route when user_agent does not match" do
754
- mock_app {
755
- user_agent(/Foo/)
756
- get '/foo' do
757
- 'Hello World'
758
- end
759
- }
760
- get '/foo'
761
- assert not_found?
762
-
763
- get '/foo', {}, { 'HTTP_USER_AGENT' => 'Foo Bar' }
764
- assert_equal 200, status
765
- assert_equal 'Hello World', body
766
- end
767
-
768
- it "treats missing user agent like an empty string" do
769
- mock_app do
770
- user_agent(/.*/)
771
- get '/' do
772
- "Hello World"
773
- end
774
- end
775
- get '/'
776
- assert_equal 200, status
777
- assert_equal 'Hello World', body
778
- end
779
-
780
- it "makes captures in user agent pattern available in params[:agent]" do
781
- mock_app {
782
- user_agent(/Foo (.*)/)
783
- get '/foo' do
784
- 'Hello ' + params[:agent].first
785
- end
786
- }
787
- get '/foo', {}, { 'HTTP_USER_AGENT' => 'Foo Bar' }
788
- assert_equal 200, status
789
- assert_equal 'Hello Bar', body
790
- end
791
-
792
- it 'matches mime_types with dots, hyphens and plus signs' do
793
- mime_types = %w(
794
- application/atom+xml
795
- application/ecmascript
796
- application/EDI-X12
797
- application/EDIFACT
798
- application/json
799
- application/javascript
800
- application/octet-stream
801
- application/ogg
802
- application/pdf
803
- application/postscript
804
- application/rdf+xml
805
- application/rss+xml
806
- application/soap+xml
807
- application/font-woff
808
- application/xhtml+xml
809
- application/xml
810
- application/xml-dtd
811
- application/xop+xml
812
- application/zip
813
- application/gzip
814
- audio/basic
815
- audio/L24
816
- audio/mp4
817
- audio/mpeg
818
- audio/ogg
819
- audio/vorbis
820
- audio/vnd.rn-realaudio
821
- audio/vnd.wave
822
- audio/webm
823
- image/gif
824
- image/jpeg
825
- image/pjpeg
826
- image/png
827
- image/svg+xml
828
- image/tiff
829
- image/vnd.microsoft.icon
830
- message/http
831
- message/imdn+xml
832
- message/partial
833
- message/rfc822
834
- model/example
835
- model/iges
836
- model/mesh
837
- model/vrml
838
- model/x3d+binary
839
- model/x3d+vrml
840
- model/x3d+xml
841
- multipart/mixed
842
- multipart/alternative
843
- multipart/related
844
- multipart/form-data
845
- multipart/signed
846
- multipart/encrypted
847
- text/cmd
848
- text/css
849
- text/csv
850
- text/html
851
- text/javascript
852
- application/javascript
853
- text/plain
854
- text/vcard
855
- text/xml
856
- video/mpeg
857
- video/mp4
858
- video/ogg
859
- video/quicktime
860
- video/webm
861
- video/x-matroska
862
- video/x-ms-wmv
863
- video/x-flv
864
- application/vnd.oasis.opendocument.text
865
- application/vnd.oasis.opendocument.spreadsheet
866
- application/vnd.oasis.opendocument.presentation
867
- application/vnd.oasis.opendocument.graphics
868
- application/vnd.ms-excel
869
- application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
870
- application/vnd.ms-powerpoint
871
- application/vnd.openxmlformats-officedocument.presentationml.presentation
872
- application/vnd.openxmlformats-officedocument.wordprocessingml.document
873
- application/vnd.mozilla.xul+xml
874
- application/vnd.google-earth.kml+xml
875
- application/x-deb
876
- application/x-dvi
877
- application/x-font-ttf
878
- application/x-javascript
879
- application/x-latex
880
- application/x-mpegURL
881
- application/x-rar-compressed
882
- application/x-shockwave-flash
883
- application/x-stuffit
884
- application/x-tar
885
- application/x-www-form-urlencoded
886
- application/x-xpinstall
887
- audio/x-aac
888
- audio/x-caf
889
- image/x-xcf
890
- text/x-gwt-rpc
891
- text/x-jquery-tmpl
892
- application/x-pkcs12
893
- application/x-pkcs12
894
- application/x-pkcs7-certificates
895
- application/x-pkcs7-certificates
896
- application/x-pkcs7-certreqresp
897
- application/x-pkcs7-mime
898
- application/x-pkcs7-mime
899
- application/x-pkcs7-signature
900
- )
901
-
902
- mime_types.each { |mime_type| assert mime_type.match(Sinatra::Request::HEADER_VALUE_WITH_PARAMS) }
903
- end
904
-
905
- it "filters by accept header" do
906
- mock_app {
907
- get '/', :provides => :xml do
908
- env['HTTP_ACCEPT']
909
- end
910
- get '/foo', :provides => :html do
911
- env['HTTP_ACCEPT']
912
- end
913
- get '/stream', :provides => 'text/event-stream' do
914
- env['HTTP_ACCEPT']
915
- end
916
- }
917
-
918
- get '/', {}, { 'HTTP_ACCEPT' => 'application/xml' }
919
- assert ok?
920
- assert_equal 'application/xml', body
921
- assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
922
-
923
- get '/', {}, {}
924
- assert ok?
925
- assert_equal '', body
926
- assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
927
-
928
- get '/', {}, { 'HTTP_ACCEPT' => '*/*' }
929
- assert ok?
930
- assert_equal '*/*', body
931
- assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
932
-
933
- get '/', {}, { 'HTTP_ACCEPT' => 'text/html;q=0.9' }
934
- assert !ok?
935
-
936
- get '/foo', {}, { 'HTTP_ACCEPT' => 'text/html;q=0.9' }
937
- assert ok?
938
- assert_equal 'text/html;q=0.9', body
939
-
940
- get '/foo', {}, { 'HTTP_ACCEPT' => '' }
941
- assert ok?
942
- assert_equal '', body
943
-
944
- get '/foo', {}, { 'HTTP_ACCEPT' => '*/*' }
945
- assert ok?
946
- assert_equal '*/*', body
947
-
948
- get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
949
- assert !ok?
950
-
951
- get '/stream', {}, { 'HTTP_ACCEPT' => 'text/event-stream' }
952
- assert ok?
953
- assert_equal 'text/event-stream', body
954
-
955
- get '/stream', {}, { 'HTTP_ACCEPT' => '' }
956
- assert ok?
957
- assert_equal '', body
958
-
959
- get '/stream', {}, { 'HTTP_ACCEPT' => '*/*' }
960
- assert ok?
961
- assert_equal '*/*', body
962
-
963
- get '/stream', {}, { 'HTTP_ACCEPT' => 'application/xml' }
964
- assert !ok?
965
- end
966
-
967
- it "filters by current Content-Type" do
968
- mock_app do
969
- before('/txt') { content_type :txt }
970
- get('*', :provides => :txt) { 'txt' }
971
-
972
- before('/html') { content_type :html }
973
- get('*', :provides => :html) { 'html' }
974
- end
975
-
976
- get '/', {}, { 'HTTP_ACCEPT' => '*/*' }
977
- assert ok?
978
- assert_equal 'text/plain;charset=utf-8', response.headers['Content-Type']
979
- assert_body 'txt'
980
-
981
- get '/txt', {}, { 'HTTP_ACCEPT' => 'text/plain' }
982
- assert ok?
983
- assert_equal 'text/plain;charset=utf-8', response.headers['Content-Type']
984
- assert_body 'txt'
985
-
986
- get '/', {}, { 'HTTP_ACCEPT' => 'text/html' }
987
- assert ok?
988
- assert_equal 'text/html;charset=utf-8', response.headers['Content-Type']
989
- assert_body 'html'
990
- end
991
-
992
- it "allows multiple mime types for accept header" do
993
- types = ['image/jpeg', 'image/pjpeg']
994
-
995
- mock_app {
996
- get '/', :provides => types do
997
- env['HTTP_ACCEPT']
998
- end
999
- }
1000
-
1001
- types.each do |type|
1002
- get '/', {}, { 'HTTP_ACCEPT' => type }
1003
- assert ok?
1004
- assert_equal type, body
1005
- assert_equal type, response.headers['Content-Type']
1006
- end
1007
- end
1008
-
1009
- it 'respects user agent preferences for the content type' do
1010
- mock_app { get('/', :provides => [:png, :html]) { content_type }}
1011
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,text/html;q=0.8' }
1012
- assert_body 'text/html;charset=utf-8'
1013
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.8,text/html;q=0.5' }
1014
- assert_body 'image/png'
1015
- end
1016
-
1017
- it 'accepts generic types' do
1018
- mock_app do
1019
- get('/', :provides => :xml) { content_type }
1020
- get('/') { 'no match' }
1021
- end
1022
- get '/', {}, { 'HTTP_ACCEPT' => 'foo/*' }
1023
- assert_body 'no match'
1024
- get '/', {}, { 'HTTP_ACCEPT' => 'application/*' }
1025
- assert_body 'application/xml;charset=utf-8'
1026
- get '/', {}, { 'HTTP_ACCEPT' => '*/*' }
1027
- assert_body 'application/xml;charset=utf-8'
1028
- end
1029
-
1030
- it 'prefers concrete over partly generic types' do
1031
- mock_app { get('/', :provides => [:png, :html]) { content_type }}
1032
- get '/', {}, { 'HTTP_ACCEPT' => 'image/*, text/html' }
1033
- assert_body 'text/html;charset=utf-8'
1034
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png, text/*' }
1035
- assert_body 'image/png'
1036
- end
1037
-
1038
- it 'prefers concrete over fully generic types' do
1039
- mock_app { get('/', :provides => [:png, :html]) { content_type }}
1040
- get '/', {}, { 'HTTP_ACCEPT' => '*/*, text/html' }
1041
- assert_body 'text/html;charset=utf-8'
1042
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png, */*' }
1043
- assert_body 'image/png'
1044
- end
1045
-
1046
- it 'prefers partly generic over fully generic types' do
1047
- mock_app { get('/', :provides => [:png, :html]) { content_type }}
1048
- get '/', {}, { 'HTTP_ACCEPT' => '*/*, text/*' }
1049
- assert_body 'text/html;charset=utf-8'
1050
- get '/', {}, { 'HTTP_ACCEPT' => 'image/*, */*' }
1051
- assert_body 'image/png'
1052
- end
1053
-
1054
- it 'respects quality with generic types' do
1055
- mock_app { get('/', :provides => [:png, :html]) { content_type }}
1056
- get '/', {}, { 'HTTP_ACCEPT' => 'image/*;q=1, text/html;q=0' }
1057
- assert_body 'image/png'
1058
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5, text/*;q=0.7' }
1059
- assert_body 'text/html;charset=utf-8'
1060
- end
1061
-
1062
- it 'supplies a default quality of 1.0' do
1063
- mock_app { get('/', :provides => [:png, :html]) { content_type }}
1064
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5, text/*' }
1065
- assert_body 'text/html;charset=utf-8'
1066
- end
1067
-
1068
- it 'orders types with equal quality by parameter count' do
1069
- mock_app do
1070
- get('/', :provides => [:png, :jpg]) { content_type }
1071
- end
1072
-
1073
- lo_png = 'image/png;q=0.5'
1074
- hi_png = 'image/png;q=0.5;profile=FOGRA40;gamma=0.8'
1075
- jpeg = 'image/jpeg;q=0.5;compress=0.25'
1076
-
1077
- get '/', {}, { 'HTTP_ACCEPT' => "#{lo_png}, #{jpeg}" }
1078
- assert_body 'image/jpeg'
1079
- get '/', {}, { 'HTTP_ACCEPT' => "#{hi_png}, #{jpeg}" }
1080
- assert_body 'image/png'
1081
- end
1082
-
1083
- it 'ignores the quality parameter when ordering by parameter count' do
1084
- mock_app do
1085
- get('/', :provides => [:png, :jpg]) { content_type }
1086
- end
1087
-
1088
- lo_png = 'image/png'
1089
- hi_png = 'image/png;profile=FOGRA40;gamma=0.8'
1090
- jpeg = 'image/jpeg;q=1.0;compress=0.25'
1091
-
1092
- get '/', {}, { 'HTTP_ACCEPT' => "#{jpeg}, #{lo_png}" }
1093
- assert_body 'image/jpeg'
1094
- get '/', {}, { 'HTTP_ACCEPT' => "#{jpeg}, #{hi_png}" }
1095
- assert_body 'image/png'
1096
- end
1097
-
1098
- it 'properly handles quoted strings in parameters' do
1099
- mock_app do
1100
- get('/', :provides => [:png, :jpg]) { content_type }
1101
- end
1102
-
1103
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5;profile=",image/jpeg,"' }
1104
- assert_body 'image/png'
1105
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,image/jpeg;q=0;x=";q=1.0"' }
1106
- assert_body 'image/png'
1107
- get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,image/jpeg;q=0;x="\";q=1.0"' }
1108
- assert_body 'image/png'
1109
- end
1110
-
1111
- it 'accepts both text/javascript and application/javascript for js' do
1112
- mock_app { get('/', :provides => :js) { content_type }}
1113
- get '/', {}, { 'HTTP_ACCEPT' => 'application/javascript' }
1114
- assert_body 'application/javascript;charset=utf-8'
1115
- get '/', {}, { 'HTTP_ACCEPT' => 'text/javascript' }
1116
- assert_body 'text/javascript;charset=utf-8'
1117
- end
1118
-
1119
- it 'accepts both text/xml and application/xml for xml' do
1120
- mock_app { get('/', :provides => :xml) { content_type }}
1121
- get '/', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1122
- assert_body 'application/xml;charset=utf-8'
1123
- get '/', {}, { 'HTTP_ACCEPT' => 'text/xml' }
1124
- assert_body 'text/xml;charset=utf-8'
1125
- end
1126
-
1127
- it 'passes a single url param as block parameters when one param is specified' do
1128
- mock_app {
1129
- get '/:foo' do |foo|
1130
- assert_equal 'bar', foo
1131
- end
1132
- }
1133
-
1134
- get '/bar'
1135
- assert ok?
1136
- end
1137
-
1138
- it 'passes multiple params as block parameters when many are specified' do
1139
- mock_app {
1140
- get '/:foo/:bar/:baz' do |foo, bar, baz|
1141
- assert_equal 'abc', foo
1142
- assert_equal 'def', bar
1143
- assert_equal 'ghi', baz
1144
- end
1145
- }
1146
-
1147
- get '/abc/def/ghi'
1148
- assert ok?
1149
- end
1150
-
1151
- it 'passes regular expression captures as block parameters' do
1152
- mock_app {
1153
- get(/^\/fo(.*)\/ba(.*)/) do |foo, bar|
1154
- assert_equal 'orooomma', foo
1155
- assert_equal 'f', bar
1156
- 'looks good'
1157
- end
1158
- }
1159
-
1160
- get '/foorooomma/baf'
1161
- assert ok?
1162
- assert_equal 'looks good', body
1163
- end
1164
-
1165
- it "supports mixing multiple splat params like /*/foo/*/* as block parameters" do
1166
- mock_app {
1167
- get '/*/foo/*/*' do |foo, bar, baz|
1168
- assert_equal 'bar', foo
1169
- assert_equal 'bling', bar
1170
- assert_equal 'baz/boom', baz
1171
- 'looks good'
1172
- end
1173
- }
1174
-
1175
- get '/bar/foo/bling/baz/boom'
1176
- assert ok?
1177
- assert_equal 'looks good', body
1178
- end
1179
-
1180
- it 'raises an ArgumentError with block arity > 1 and too many values' do
1181
- mock_app do
1182
- get '/:foo/:bar/:baz' do |foo, bar|
1183
- 'quux'
1184
- end
1185
- end
1186
-
1187
- assert_raises(ArgumentError) { get '/a/b/c' }
1188
- end
1189
-
1190
- it 'raises an ArgumentError with block param arity > 1 and too few values' do
1191
- mock_app {
1192
- get '/:foo/:bar' do |foo, bar, baz|
1193
- 'quux'
1194
- end
1195
- }
1196
-
1197
- assert_raises(ArgumentError) { get '/a/b' }
1198
- end
1199
-
1200
- it 'succeeds if no block parameters are specified' do
1201
- mock_app {
1202
- get '/:foo/:bar' do
1203
- 'quux'
1204
- end
1205
- }
1206
-
1207
- get '/a/b'
1208
- assert ok?
1209
- assert_equal 'quux', body
1210
- end
1211
-
1212
- it 'passes all params with block param arity -1 (splat args)' do
1213
- mock_app {
1214
- get '/:foo/:bar' do |*args|
1215
- args.join
1216
- end
1217
- }
1218
-
1219
- get '/a/b'
1220
- assert ok?
1221
- assert_equal 'ab', body
1222
- end
1223
-
1224
- it 'allows custom route-conditions to be set via route options' do
1225
- protector = Module.new {
1226
- def protect(*args)
1227
- condition {
1228
- unless authorize(params["user"], params["password"])
1229
- halt 403, "go away"
1230
- end
1231
- }
1232
- end
1233
- }
1234
-
1235
- mock_app {
1236
- register protector
1237
-
1238
- helpers do
1239
- def authorize(username, password)
1240
- username == "foo" && password == "bar"
1241
- end
1242
- end
1243
-
1244
- get "/", :protect => true do
1245
- "hey"
1246
- end
1247
- }
1248
-
1249
- get "/"
1250
- assert forbidden?
1251
- assert_equal "go away", body
1252
-
1253
- get "/", :user => "foo", :password => "bar"
1254
- assert ok?
1255
- assert_equal "hey", body
1256
- end
1257
-
1258
- # NOTE Block params behaves differently under 1.8 and 1.9. Under 1.8, block
1259
- # param arity is lax: declaring a mismatched number of block params results
1260
- # in a warning. Under 1.9, block param arity is strict: mismatched block
1261
- # arity raises an ArgumentError.
1262
-
1263
- if RUBY_VERSION >= '1.9'
1264
-
1265
- it 'raises an ArgumentError with block param arity 1 and no values' do
1266
- mock_app {
1267
- get '/foo' do |foo|
1268
- 'quux'
1269
- end
1270
- }
1271
-
1272
- assert_raises(ArgumentError) { get '/foo' }
1273
- end
1274
-
1275
- it 'raises an ArgumentError with block param arity 1 and too many values' do
1276
- mock_app {
1277
- get '/:foo/:bar/:baz' do |foo|
1278
- 'quux'
1279
- end
1280
- }
1281
-
1282
- assert_raises(ArgumentError) { get '/a/b/c' }
1283
- end
1284
-
1285
- else
1286
-
1287
- it 'does not raise an ArgumentError with block param arity 1 and no values' do
1288
- mock_app {
1289
- get '/foo' do |foo|
1290
- 'quux'
1291
- end
1292
- }
1293
-
1294
- silence_warnings { get '/foo' }
1295
- assert ok?
1296
- assert_equal 'quux', body
1297
- end
1298
-
1299
- it 'does not raise an ArgumentError with block param arity 1 and too many values' do
1300
- mock_app {
1301
- get '/:foo/:bar/:baz' do |foo|
1302
- 'quux'
1303
- end
1304
- }
1305
-
1306
- silence_warnings { get '/a/b/c' }
1307
- assert ok?
1308
- assert_equal 'quux', body
1309
- end
1310
-
1311
- end
1312
-
1313
- it "matches routes defined in superclasses" do
1314
- base = Class.new(Sinatra::Base)
1315
- base.get('/foo') { 'foo in baseclass' }
1316
-
1317
- mock_app(base) {
1318
- get('/bar') { 'bar in subclass' }
1319
- }
1320
-
1321
- get '/foo'
1322
- assert ok?
1323
- assert_equal 'foo in baseclass', body
1324
-
1325
- get '/bar'
1326
- assert ok?
1327
- assert_equal 'bar in subclass', body
1328
- end
1329
-
1330
- it "matches routes in subclasses before superclasses" do
1331
- base = Class.new(Sinatra::Base)
1332
- base.get('/foo') { 'foo in baseclass' }
1333
- base.get('/bar') { 'bar in baseclass' }
1334
-
1335
- mock_app(base) {
1336
- get('/foo') { 'foo in subclass' }
1337
- }
1338
-
1339
- get '/foo'
1340
- assert ok?
1341
- assert_equal 'foo in subclass', body
1342
-
1343
- get '/bar'
1344
- assert ok?
1345
- assert_equal 'bar in baseclass', body
1346
- end
1347
-
1348
- it "adds hostname condition when it is in options" do
1349
- mock_app {
1350
- get '/foo', :host => 'host' do
1351
- 'foo'
1352
- end
1353
- }
1354
-
1355
- get '/foo'
1356
- assert not_found?
1357
- end
1358
-
1359
- it 'allows using call to fire another request internally' do
1360
- mock_app do
1361
- get '/foo' do
1362
- status, headers, body = call env.merge("PATH_INFO" => '/bar')
1363
- [status, headers, body.each.map(&:upcase)]
1364
- end
1365
-
1366
- get '/bar' do
1367
- "bar"
1368
- end
1369
- end
1370
-
1371
- get '/foo'
1372
- assert ok?
1373
- assert_body "BAR"
1374
- end
1375
-
1376
- it 'plays well with other routing middleware' do
1377
- middleware = Sinatra.new
1378
- inner_app = Sinatra.new { get('/foo') { 'hello' } }
1379
- builder = Rack::Builder.new do
1380
- use middleware
1381
- map('/test') { run inner_app }
1382
- end
1383
-
1384
- @app = builder.to_app
1385
- get '/test/foo'
1386
- assert ok?
1387
- assert_body 'hello'
1388
- end
1389
-
1390
- it 'returns the route signature' do
1391
- signature = list = nil
1392
-
1393
- mock_app do
1394
- signature = post('/') { }
1395
- list = routes['POST']
1396
- end
1397
-
1398
- assert_equal Array, signature.class
1399
- assert_equal 4, signature.length
1400
- assert list.include?(signature)
1401
- end
1402
-
1403
- it "sets env['sinatra.route'] to the matched route" do
1404
- mock_app do
1405
- after do
1406
- assert_equal 'GET /users/:id/status', env['sinatra.route']
1407
- end
1408
- get('/users/:id/status') { 'ok' }
1409
- end
1410
- get '/users/1/status'
1411
- end
1412
- end