howl-router 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/test/howl_test.rb ADDED
@@ -0,0 +1,101 @@
1
+ require File.expand_path('../../lib/howl-router', __FILE__)
2
+ $:.unshift(File.dirname(__FILE__))
3
+ require 'helper'
4
+
5
+ describe Howl do
6
+ setup{ @howl = howl }
7
+
8
+ describe "normal routing" do
9
+ before(:each){ @howl.reset! }
10
+
11
+ should "basic route" do
12
+ @howl.add(:get, "/"){ "index" }
13
+ @howl.add(:get, "/users"){ "users" }
14
+ get("/")
15
+ assert_equal "index", body
16
+ get("/users")
17
+ assert_equal "users", body
18
+ end
19
+
20
+ should "ignore trailing delimiters for basic route" do
21
+ @howl.add(:get, "/"){ "index" }
22
+ @howl.add(:get, "/users"){ "users" }
23
+
24
+ get("")
25
+ assert_equal "index", body
26
+ get("/users/")
27
+ assert_equal "users", body
28
+ end
29
+
30
+ should "use pattern" do
31
+ @howl.add(:get, "/:id"){|params| "show #{params[:id]}" }
32
+ @howl.add(:get, "/:id.:ext"){|params| "show #{params[:id]}.#{params[:ext]}" }
33
+
34
+ get("/1")
35
+ assert_equal "show 1", body
36
+ get("/foo")
37
+ assert_equal "show foo", body
38
+ get("/1.json")
39
+ assert_equal "show 1.json", body
40
+ get("/foo.xml")
41
+ assert_equal "show foo.xml", body
42
+ end
43
+
44
+ should "use capture" do
45
+ id_route = @howl.add(:get, "/:id"){|params| "show #{params[:id]}" }
46
+ id_route.capture[:id] = /\d+/
47
+
48
+ id_with_ext_route = @howl.add(:get, "/:id.:ext"){|params| "show #{params[:id]}.#{params[:ext]}" }
49
+ id_with_ext_route.capture[:id] = /(foo|bar)/
50
+ id_with_ext_route.capture[:ext] = %w[html json]
51
+
52
+ get("/1")
53
+ assert_equal "show 1", body
54
+ get("/foo")
55
+ assert_equal "Not Found", body
56
+ get("/foo.json")
57
+ assert_equal "show foo.json", body
58
+ get("/baz.json")
59
+ assert_equal "Not Found", body
60
+ get("/foo.html")
61
+ assert_equal "show foo.html", body
62
+ get("/foo.xml")
63
+ assert_equal "Not Found", body
64
+ end
65
+ end
66
+ describe "regexp routing" do
67
+ before(:each){ @howl.reset! }
68
+
69
+ should "basic route of regexp" do
70
+ @howl.add(:get, /\/(\d+)/){|params| params[:captures].join(",") }
71
+ @howl.add(:get, /\/(foo|bar)(baz)?/){|params| params[:captures].compact.join(",") }
72
+
73
+ get("/123")
74
+ assert_equal "123", body
75
+ get("/foo")
76
+ assert_equal "foo", body
77
+ get("/foobaz")
78
+ assert_equal "foo,baz", body
79
+ end
80
+ end
81
+
82
+ describe "generate path" do
83
+ before(:each){ @howl.reset! }
84
+
85
+ should "basic route of regexp" do
86
+ index = @howl.add(:get, "/"){}
87
+ index.name = :index
88
+ foo_bar = @howl.add(:post, "/foo/bar"){}
89
+ foo_bar.name = :foo_bar
90
+ users = @howl.add(:get, "/users/:user_id"){}
91
+ users.name = :users
92
+
93
+ assert_equal @howl.path(:index), "/"
94
+ assert_equal @howl.path(:foo_bar), "/foo/bar"
95
+ assert_equal @howl.path(:users, :user_id => 1), "/users/1"
96
+ assert_equal @howl.path(:users, :user_id => 1, :query => "string"), "/users/1?query=string"
97
+ end
98
+ end
99
+
100
+
101
+ end
@@ -0,0 +1,1918 @@
1
+ require File.expand_path('../../lib/howl-router/padrino', __FILE__)
2
+ $:.unshift(File.dirname(__FILE__))
3
+ require 'helper'
4
+
5
+ class FooError < RuntimeError; end
6
+
7
+ describe "Howl::Padrino" do
8
+ setup do
9
+ Padrino::Application.send(:register, Padrino::Rendering)
10
+ Padrino::Application.send(:register, Howl::Padrino)
11
+ Padrino::Rendering::DEFAULT_RENDERING_OPTIONS[:strict_format] = false
12
+ end
13
+
14
+ should "serve static files with simple cache control" do
15
+ mock_app do
16
+ set :static_cache_control, :public
17
+ set :public_folder, File.dirname(__FILE__)
18
+ end
19
+ get "/#{File.basename(__FILE__)}"
20
+ assert headers.has_key?('Cache-Control')
21
+ assert_equal headers['Cache-Control'], 'public'
22
+ end # static simple
23
+
24
+ should "serve static files with cache control and max_age" do
25
+ mock_app do
26
+ set :static_cache_control, [:public, :must_revalidate, {:max_age => 300}]
27
+ set :public_folder, File.dirname(__FILE__)
28
+ end
29
+ get "/#{File.basename(__FILE__)}"
30
+ assert headers.has_key?('Cache-Control')
31
+ assert_equal headers['Cache-Control'], 'public, must-revalidate, max-age=300'
32
+ end # static max_age
33
+
34
+ should 'ignore trailing delimiters for basic route' do
35
+ mock_app do
36
+ get("/foo"){ "okey" }
37
+ get(:test) { "tester" }
38
+ end
39
+ get "/foo"
40
+ assert_equal "okey", body
41
+ get "/foo/"
42
+ assert_equal "okey", body
43
+ get "/test"
44
+ assert_equal "tester", body
45
+ get "/test/"
46
+ assert_equal "tester", body
47
+ end
48
+
49
+ should 'fail with unrecognized route exception when not found' do
50
+ mock_app do
51
+ get(:index){ "okey" }
52
+ end
53
+ get @app.url_for(:index)
54
+ assert_equal "okey", body
55
+ assert_raises(Padrino::Routing::UnrecognizedException) {
56
+ get @app.url_for(:fake)
57
+ }
58
+ end
59
+
60
+ should 'accept regexp routes' do
61
+ mock_app do
62
+ get(%r./fob|/baz.) { "regexp" }
63
+ get("/foo") { "str" }
64
+ get %r./([0-9]+)/. do |num|
65
+ "Your lucky number: #{num} #{params[:captures].first}"
66
+ end
67
+ get %r./page/([0-9]+)|/. do |num|
68
+ "My lucky number: #{num} #{params[:captures].first}"
69
+ end
70
+ end
71
+ get "/foo"
72
+ assert_equal "str", body
73
+ get "/fob"
74
+ assert_equal "regexp", body
75
+ get "/baz"
76
+ assert_equal "regexp", body
77
+ get "/321/"
78
+ assert_equal "Your lucky number: 321 321", body
79
+ get "/page/99"
80
+ assert_equal "My lucky number: 99 99", body
81
+ end
82
+
83
+ should 'accept regexp routes with generate with :generate_with' do
84
+ mock_app do
85
+ get(%r{/fob|/baz}, :name => :foo, :generate_with => '/fob') { "regexp" }
86
+ end
87
+ assert_equal "/fob", @app.url(:foo)
88
+ end
89
+
90
+ should "parse routes with question marks" do
91
+ mock_app do
92
+ get("/foo/?"){ "okey" }
93
+ post('/unauthenticated/?') { "no access" }
94
+ end
95
+ get "/foo"
96
+ assert_equal "okey", body
97
+ get "/foo/"
98
+ assert_equal "okey", body
99
+ post "/unauthenticated"
100
+ assert_equal "no access", body
101
+ post "/unauthenticated/"
102
+ assert_equal "no access", body
103
+ end
104
+
105
+ should 'parse routes that are encoded' do
106
+ mock_app do
107
+ get('/щч') { 'success!' }
108
+ end
109
+ get(URI.escape('/щч'))
110
+ assert_equal 'success!', body
111
+ end
112
+
113
+ should 'encode params using UTF-8' do
114
+ #skip unless ''.respond_to?(:encoding) # for 1.8.7
115
+
116
+ mock_app do
117
+ get('/:foo') { params[:foo].encoding.name }
118
+ end
119
+ get '/bar'
120
+ assert_equal 'UTF-8', body
121
+ end
122
+
123
+ should 'match correctly similar paths' do
124
+ mock_app do
125
+ get("/my/:foo_id"){ params[:foo_id] }
126
+ get("/my/:bar_id/bar"){ params[:bar_id] }
127
+ end
128
+ get "/my/1"
129
+ assert_equal "1", body
130
+ get "/my/2/bar"
131
+ assert_equal "2", body
132
+ end
133
+
134
+ should "match user agents" do
135
+ app = mock_app do
136
+ get("/main", :agent => /IE/){ "hello IE" }
137
+ get("/main"){ "hello" }
138
+ end
139
+ get "/main"
140
+ assert_equal "hello", body
141
+ get "/main", {}, {'HTTP_USER_AGENT' => 'This is IE'}
142
+ assert_equal "hello IE", body
143
+ end
144
+
145
+ should "use regex for parts of a route" do
146
+ app = mock_app do
147
+ get("/main/:id", :id => /\d+/){ "hello #{params[:id]}" }
148
+ end
149
+ get "/main/123"
150
+ assert_equal "hello 123", body
151
+ get "/main/asd"
152
+ assert_equal 404, status
153
+ end
154
+
155
+ should "parse params when use regex for parts of a route" do
156
+ mock_app do
157
+ post :index, :with => [:foo, :bar], :bar => /.+/ do
158
+ "show #{params[:foo]}"
159
+ end
160
+
161
+ get :index, :map => '/mystuff/:a_id/boing/:boing_id' do
162
+ "show #{params[:a_id]} and #{params[:boing_id]}"
163
+ end
164
+ end
165
+ get "/mystuff/5/boing/2"
166
+ assert_equal "show 5 and 2", body
167
+ end
168
+
169
+ should "not generate overlapping head urls" do
170
+ app = mock_app do
171
+ get("/main"){ "hello" }
172
+ post("/main"){ "hello" }
173
+ end
174
+ assert_equal 3, app.routes.size, "should generate GET, HEAD and PUT"
175
+ assert_equal "GET", app.routes[0].request_methods.first
176
+ assert_equal "HEAD", app.routes[1].request_methods.first
177
+ assert_equal "POST", app.routes[2].request_methods.first
178
+ end
179
+
180
+ should 'generate basic urls' do
181
+ mock_app do
182
+ get(:foo){ "/foo" }
183
+ get(:foo, :with => :id){ |id| "/foo/#{id}" }
184
+ get([:foo, :id]){ |id| "/foo/#{id}" }
185
+ get(:hash, :with => :id){ url(:hash, :id => 1) }
186
+ get([:hash, :id]){ url(:hash, :id => 1) }
187
+ get(:array, :with => :id){ url(:array, 23) }
188
+ get([:array, :id]){ url(:array, 23) }
189
+ get(:hash_with_extra, :with => :id){ url(:hash_with_extra, :id => 1, :query => 'string') }
190
+ get([:hash_with_extra, :id]){ url(:hash_with_extra, :id => 1, :query => 'string') }
191
+ get(:array_with_extra, :with => :id){ url(:array_with_extra, 23, :query => 'string') }
192
+ get([:array_with_extra, :id]){ url(:array_with_extra, 23, :query => 'string') }
193
+ get("/old-bar/:id"){ params[:id] }
194
+ post(:mix, :map => "/mix-bar/:id"){ params[:id] }
195
+ get(:mix, :map => "/mix-bar/:id"){ params[:id] }
196
+ end
197
+ get "/foo"
198
+ assert_equal "/foo", body
199
+ get "/foo/123"
200
+ assert_equal "/foo/123", body
201
+ get "/hash/2"
202
+ assert_equal "/hash/1", body
203
+ get "/array/23"
204
+ assert_equal "/array/23", body
205
+ get "/hash_with_extra/1"
206
+ assert_equal "/hash_with_extra/1?query=string", body
207
+ get "/array_with_extra/23"
208
+ assert_equal "/array_with_extra/23?query=string", body
209
+ get "/old-bar/3"
210
+ assert_equal "3", body
211
+ post "/mix-bar/4"
212
+ assert_equal "4", body
213
+ get "/mix-bar/4"
214
+ assert_equal "4", body
215
+ end
216
+
217
+ should 'generate url with format' do
218
+ mock_app do
219
+ get(:a, :provides => :any){ url(:a, :format => :json) }
220
+ get(:b, :provides => :js){ url(:b, :format => :js) }
221
+ get(:c, :provides => [:js, :json]){ url(:c, :format => :json) }
222
+ get(:d, :provides => [:html, :js]){ url(:d, :format => :js, :foo => :bar) }
223
+ end
224
+ get "/a.js"
225
+ assert_equal "/a.json", body
226
+ get "/b.js"
227
+ assert_equal "/b.js", body
228
+ get "/b.ru"
229
+ assert_equal 404, status
230
+ get "/c.js"
231
+ assert_equal "/c.json", body
232
+ get "/c.json"
233
+ assert_equal "/c.json", body
234
+ get "/c.ru"
235
+ assert_equal 404, status
236
+ get "/d"
237
+ assert_equal "/d.js?foo=bar", body
238
+ get "/d.js"
239
+ assert_equal "/d.js?foo=bar", body
240
+ get "/e.xml"
241
+ assert_equal 404, status
242
+ end
243
+
244
+ should 'generate absolute urls' do
245
+ mock_app do
246
+ get(:hash, :with => :id){ absolute_url(:hash, :id => 1) }
247
+ end
248
+ get "/hash/2"
249
+ assert_equal "http://example.org/hash/1", body
250
+ get "https://example.org/hash/2"
251
+ assert_equal "https://example.org/hash/1", body
252
+ end
253
+
254
+ should 'generate proper absolute urls for mounted apps' do
255
+ class Test < Padrino::Application
256
+ get :foo do
257
+ absolute_url(:foo, :id => 1)
258
+ end
259
+ end
260
+ Padrino.mount("Test").to("/test")
261
+ @app = Padrino.application
262
+ get('/test/foo')
263
+ assert_equal 'http://example.org/test/foo?id=1', body
264
+ end
265
+
266
+ should 'allow regex url with format' do
267
+ mock_app do
268
+ get(/.*/, :provides => :any) { "regexp" }
269
+ end
270
+ get "/anything"
271
+ assert_equal "regexp", body
272
+ end
273
+
274
+ should 'use padrino url method' do
275
+ mock_app do
276
+ end
277
+
278
+ assert_equal @app.method(:url).owner, Howl::Padrino::ClassMethods
279
+ end
280
+
281
+ should 'work correctly with sinatra redirects' do
282
+ mock_app do
283
+ get(:index) { redirect url(:index) }
284
+ get(:google) { redirect "http://google.com" }
285
+ get("/foo") { redirect "/bar" }
286
+ get("/bar") { "Bar" }
287
+ end
288
+
289
+ get "/"
290
+ assert_equal "http://example.org/", headers['Location']
291
+ get "/google"
292
+ assert_equal "http://google.com", headers['Location']
293
+ get "/foo"
294
+ assert_equal "http://example.org/bar", headers['Location']
295
+ end
296
+
297
+ should "return 406 on Accept-Headers it does not provide" do
298
+ mock_app do
299
+ get(:a, :provides => [:html, :js]){ content_type }
300
+ end
301
+
302
+ get "/a", {}, {"HTTP_ACCEPT" => "application/yaml"}
303
+ assert_equal 406, status
304
+ end
305
+
306
+ should "return 406 on file extensions it does not provide and flag is set" do
307
+ mock_app do
308
+ enable :treat_format_as_accept
309
+ get(:a, :provides => [:html, :js]){ content_type }
310
+ end
311
+
312
+ get "/a.xml", {}, {}
313
+ assert_equal 406, status
314
+ end
315
+
316
+ should "return 404 on file extensions it does not provide and flag is not set" do
317
+ mock_app do
318
+ get(:a, :provides => [:html, :js]){ content_type }
319
+ end
320
+
321
+ get "/a.xml", {}, {}
322
+ assert_equal 404, status
323
+ end
324
+
325
+ should "not set content_type to :html if Accept */* and html not in provides" do
326
+ mock_app do
327
+ get("/foo", :provides => [:json, :xml]) { content_type.to_s }
328
+ end
329
+
330
+ get '/foo', {}, { 'HTTP_ACCEPT' => '*/*;q=0.5' }
331
+ assert_equal 'json', body
332
+ end
333
+
334
+ should "set content_type to :json if Accept contains */*" do
335
+ mock_app do
336
+ get("/foo", :provides => [:json]) { content_type.to_s }
337
+ end
338
+
339
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' }
340
+ assert_equal 'json', body
341
+ end
342
+
343
+ should 'set and get content_type' do
344
+ mock_app do
345
+ get("/foo"){ content_type(:json); content_type.to_s }
346
+ end
347
+ get "/foo"
348
+ assert_equal 'application/json;charset=utf-8', content_type
349
+ assert_equal 'json', body
350
+ end
351
+
352
+ should "send the appropriate number of params" do
353
+ mock_app do
354
+ get('/id/:user_id', :provides => [:json]) { |user_id, format| user_id}
355
+ end
356
+ get '/id/5.json'
357
+ assert_equal '5', body
358
+ end
359
+
360
+ should "allow .'s in param values" do
361
+ #skip
362
+ mock_app do
363
+ get('/id/:email', :provides => [:json]) { |email, format| [email, format] * '/' }
364
+ end
365
+ get '/id/foo@bar.com.json'
366
+ assert_equal 'foo@bar.com/json', body
367
+ end
368
+
369
+ should "set correct content_type for Accept not equal to */* even if */* also provided" do
370
+ mock_app do
371
+ get("/foo", :provides => [:html, :js, :xml]) { content_type.to_s }
372
+ end
373
+
374
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
375
+ assert_equal 'js', body
376
+ end
377
+
378
+ should "return the first content type in provides if accept header is empty" do
379
+ mock_app do
380
+ get(:a, :provides => [:js]){ content_type.to_s }
381
+ end
382
+
383
+ get "/a", {}, {}
384
+ assert_equal "js", body
385
+ end
386
+
387
+ should "not default to HTML if HTML is not provided and no type is given" do
388
+ mock_app do
389
+ get(:a, :provides => [:js]){ content_type }
390
+ end
391
+
392
+ get "/a", {}, {}
393
+ assert_equal "application/javascript;charset=utf-8", content_type
394
+ end
395
+
396
+ should "not match routes if url_format and http_accept is provided but not included" do
397
+ mock_app do
398
+ get(:a, :provides => [:js, :html]){ content_type }
399
+ end
400
+
401
+ get "/a.xml", {}, {"HTTP_ACCEPT" => "text/html"}
402
+ assert_equal 404, status
403
+ end
404
+
405
+ should "generate routes for format simple" do
406
+ mock_app do
407
+ get(:foo, :provides => [:html, :rss]) { render :haml, "Test" }
408
+ end
409
+ get "/foo"
410
+ assert_equal "Test\n", body
411
+ get "/foo.rss"
412
+ assert_equal "Test\n", body
413
+ end
414
+
415
+ should "should inject the controller name into the request" do
416
+ mock_app do
417
+ controller :posts do
418
+ get(:index) { request.controller }
419
+ controller :mini do
420
+ get(:index) { request.controller }
421
+ end
422
+ end
423
+ end
424
+ get "/posts"
425
+ assert_equal "posts", body
426
+ get "/mini"
427
+ assert_equal "mini", body
428
+ end
429
+
430
+ should "should inject the action name into the request" do
431
+ mock_app do
432
+ controller :posts do
433
+ get('/omnomnom(/:id)') { request.action.inspect }
434
+ controller :mini do
435
+ get([:a, :b, :c]) { request.action.inspect }
436
+ end
437
+ end
438
+ end
439
+ get "/posts/omnomnom"
440
+ assert_equal "\"/omnomnom(/:id)\"", body
441
+ get "/mini/a/b/c"
442
+ assert_equal ":a", body
443
+ end
444
+
445
+ should "support not_found" do
446
+ mock_app do
447
+ not_found { 'whatever' }
448
+
449
+ get :index, :map => "/" do
450
+ 'index'
451
+ end
452
+ end
453
+ get '/wrong'
454
+ assert_equal 404, status
455
+ assert_equal 'whatever', body
456
+ get '/'
457
+ assert_equal 'index', body
458
+ assert_equal 200, status
459
+ end
460
+
461
+ should "should inject the route into the request" do
462
+ mock_app do
463
+ controller :posts do
464
+ get(:index) { request.route_obj.name.to_s }
465
+ end
466
+ end
467
+ get "/posts"
468
+ assert_equal "posts_index", body
469
+ end
470
+
471
+ should "preserve the format if you set it manually" do
472
+ mock_app do
473
+ before do
474
+ params[:format] = "json"
475
+ end
476
+
477
+ get "test", :provides => [:html, :json] do
478
+ content_type.inspect
479
+ end
480
+ end
481
+ get "/test"
482
+ assert_equal ":json", body
483
+ get "/test.html"
484
+ assert_equal ":json", body
485
+ get "/test.php"
486
+ assert_equal ":json", body
487
+ end
488
+
489
+ should "correctly accept '.' in the route" do
490
+ mock_app do
491
+ get "test.php", :provides => [:html, :json] do
492
+ content_type.inspect
493
+ end
494
+ end
495
+ get "/test.php"
496
+ assert_equal ":html", body
497
+ get "/test.php.json"
498
+ assert_equal ":json", body
499
+ end
500
+
501
+ should "correctly accept priority of format" do
502
+ mock_app do
503
+ get "test.php", :provides => [:html, :json, :xml] do
504
+ content_type.inspect
505
+ end
506
+ end
507
+
508
+ get "/test.php"
509
+ assert_equal ":html", body
510
+ get "/test.php", {}, { 'HTTP_ACCEPT' => 'application/xml' }
511
+ assert_equal ":xml", body
512
+ get "/test.php?format=json", { 'HTTP_ACCEPT' => 'application/xml' }
513
+ assert_equal ":json", body
514
+ get "/test.php.json?format=html", { 'HTTP_ACCEPT' => 'application/xml' }
515
+ assert_equal ":json", body
516
+ end
517
+
518
+ should "generate routes for format with controller" do
519
+ mock_app do
520
+ controller :posts do
521
+ get(:index, :provides => [:html, :rss, :atom, :js]) { render :haml, "Index.#{content_type}" }
522
+ get(:show, :with => :id, :provides => [:html, :rss, :atom]) { render :haml, "Show.#{content_type}" }
523
+ end
524
+ end
525
+ get "/posts"
526
+ assert_equal "Index.html\n", body
527
+ get "/posts.rss"
528
+ assert_equal "Index.rss\n", body
529
+ get "/posts.atom"
530
+ assert_equal "Index.atom\n", body
531
+ get "/posts.js"
532
+ assert_equal "Index.js\n", body
533
+ get "/posts/show/5"
534
+ assert_equal "Show.html\n", body
535
+ get "/posts/show/5.rss"
536
+ assert_equal "Show.rss\n", body
537
+ get "/posts/show/10.atom"
538
+ assert_equal "Show.atom\n", body
539
+ end
540
+
541
+ should 'map routes' do
542
+ mock_app do
543
+ get(:bar){ "bar" }
544
+ end
545
+ get "/bar"
546
+ assert_equal "bar", body
547
+ assert_equal "/bar", @app.url(:bar)
548
+ end
549
+
550
+ should 'remove index from path' do
551
+ mock_app do
552
+ get(:index){ "index" }
553
+ get("/accounts/index"){ "accounts" }
554
+ end
555
+ get "/"
556
+ assert_equal "index", body
557
+ assert_equal "/", @app.url(:index)
558
+ get "/accounts/index"
559
+ assert_equal "accounts", body
560
+ end
561
+
562
+ should 'remove index from path with params' do
563
+ mock_app do
564
+ get(:index, :with => :name){ "index with #{params[:name]}" }
565
+ end
566
+ get "/bobby"
567
+ assert_equal "index with bobby", body
568
+ assert_equal "/john", @app.url(:index, :name => "john")
569
+ end
570
+
571
+ should 'parse named params' do
572
+ mock_app do
573
+ get(:print, :with => :id){ "Im #{params[:id]}" }
574
+ end
575
+ get "/print/9"
576
+ assert_equal "Im 9", body
577
+ assert_equal "/print/9", @app.url(:print, :id => 9)
578
+ end
579
+
580
+ should '405 on wrong request_method' do
581
+ mock_app do
582
+ post('/bar'){ "bar" }
583
+ end
584
+ get "/bar"
585
+ assert_equal 405, status
586
+ end
587
+
588
+ should 'respond to' do
589
+ mock_app do
590
+ get(:a, :provides => :js){ "js" }
591
+ get(:b, :provides => :any){ "any" }
592
+ get(:c, :provides => [:js, :json]){ "js,json" }
593
+ get(:d, :provides => [:html, :js]){ "html,js"}
594
+ end
595
+ get "/a"
596
+ assert_equal 200, status
597
+ assert_equal "js", body
598
+ get "/a.js"
599
+ assert_equal "js", body
600
+ get "/b"
601
+ assert_equal "any", body
602
+ # TODO randomly fails in minitest :(
603
+ # assert_raises(RuntimeError) { get "/b.foo" }
604
+ get "/c"
605
+ assert_equal 200, status
606
+ assert_equal "js,json", body
607
+ get "/c.js"
608
+ assert_equal "js,json", body
609
+ get "/c.json"
610
+ assert_equal "js,json", body
611
+ get "/d"
612
+ assert_equal "html,js", body
613
+ get "/d.js"
614
+ assert_equal "html,js", body
615
+ end
616
+
617
+ should 'respond_to and set content_type' do
618
+ Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
619
+ mock_app do
620
+ get :a, :provides => :any do
621
+ case content_type
622
+ when :js then "js"
623
+ when :json then "json"
624
+ when :foo then "foo"
625
+ when :html then "html"
626
+ end
627
+ end
628
+ end
629
+ get "/a.js"
630
+ assert_equal "js", body
631
+ assert_equal 'application/javascript;charset=utf-8', response["Content-Type"]
632
+ get "/a.json"
633
+ assert_equal "json", body
634
+ assert_equal 'application/json;charset=utf-8', response["Content-Type"]
635
+ get "/a.foo"
636
+ assert_equal "foo", body
637
+ assert_equal 'application/foo;charset=utf-8', response["Content-Type"]
638
+ get "/a"
639
+ assert_equal "html", body
640
+ assert_equal 'text/html;charset=utf-8', response["Content-Type"]
641
+ end
642
+
643
+ should 'use controllers' do
644
+ mock_app do
645
+ controller "/admin" do
646
+ get("/"){ "index" }
647
+ get("/show/:id"){ "show #{params[:id]}" }
648
+ end
649
+ end
650
+ get "/admin"
651
+ assert_equal "index", body
652
+ get "/admin/show/1"
653
+ assert_equal "show 1", body
654
+ end
655
+
656
+ should 'use named controllers' do
657
+ mock_app do
658
+ controller :admin do
659
+ get(:index, :with => :id){ params[:id] }
660
+ get(:show, :with => :id){ "show #{params[:id]}" }
661
+ end
662
+ controllers :foo, :bar do
663
+ get(:index){ "foo_bar_index" }
664
+ end
665
+ end
666
+ get "/admin/1"
667
+ assert_equal "1", body
668
+ get "/admin/show/1"
669
+ assert_equal "show 1", body
670
+ assert_equal "/admin/1", @app.url(:admin_index, :id => 1)
671
+ assert_equal "/admin/show/1", @app.url(:admin_show, :id => 1)
672
+ get "/foo/bar"
673
+ assert_equal "foo_bar_index", body
674
+ end
675
+
676
+ should 'use map and with' do
677
+ mock_app do
678
+ get :index, :map => '/bugs', :with => :id do
679
+ params[:id]
680
+ end
681
+ end
682
+ get '/bugs/4'
683
+ assert_equal '4', body
684
+ assert_equal "/bugs/4", @app.url(:index, :id => 4)
685
+ end
686
+
687
+ should "ignore trailing delimiters within a named controller" do
688
+ mock_app do
689
+ controller :posts do
690
+ get(:index, :provides => [:html, :js]){ "index" }
691
+ get(:new) { "new" }
692
+ get(:show, :with => :id){ "show #{params[:id]}" }
693
+ end
694
+ end
695
+ get "/posts"
696
+ assert_equal "index", body
697
+ get "/posts/"
698
+ assert_equal "index", body
699
+ get "/posts.js"
700
+ assert_equal "index", body
701
+ get "/posts.js/"
702
+ assert_equal "index", body
703
+ get "/posts/new"
704
+ assert_equal "new", body
705
+ get "/posts/new/"
706
+ assert_equal "new", body
707
+ end
708
+
709
+ should "ignore trailing delimiters within a named controller for unnamed actions" do
710
+ mock_app do
711
+ controller :accounts do
712
+ get("/") { "account_index" }
713
+ get("/new") { "new" }
714
+ end
715
+ controller :votes do
716
+ get("/") { "vote_index" }
717
+ end
718
+ end
719
+ get "/accounts"
720
+ assert_equal "account_index", body
721
+ get "/accounts/"
722
+ assert_equal "account_index", body
723
+ get "/accounts/new"
724
+ assert_equal "new", body
725
+ get "/accounts/new/"
726
+ assert_equal "new", body
727
+ get "/votes"
728
+ assert_equal "vote_index", body
729
+ get "/votes/"
730
+ assert_equal "vote_index", body
731
+ end
732
+
733
+ should 'use named controllers with array routes' do
734
+ mock_app do
735
+ controller :admin do
736
+ get(:index){ "index" }
737
+ get(:show, :with => :id){ "show #{params[:id]}" }
738
+ end
739
+ controllers :foo, :bar do
740
+ get(:index){ "foo_bar_index" }
741
+ end
742
+ end
743
+ get "/admin"
744
+ assert_equal "index", body
745
+ get "/admin/show/1"
746
+ assert_equal "show 1", body
747
+ assert_equal "/admin", @app.url(:admin, :index)
748
+ assert_equal "/admin/show/1", @app.url(:admin, :show, :id => 1)
749
+ get "/foo/bar"
750
+ assert_equal "foo_bar_index", body
751
+ end
752
+
753
+ should "support a reindex action and remove index inside controller" do
754
+ mock_app do
755
+ controller :posts do
756
+ get(:index){ "index" }
757
+ get(:reindex){ "reindex" }
758
+ end
759
+ end
760
+ get "/posts"
761
+ assert_equal "index", body
762
+ get "/posts/reindex"
763
+ assert_equal "/posts/reindex", @app.url(:posts, :reindex)
764
+ assert_equal "reindex", body
765
+ end
766
+
767
+ should 'use uri_root' do
768
+ mock_app do
769
+ get(:foo){ "foo" }
770
+ end
771
+ @app.uri_root = '/'
772
+ assert_equal "/foo", @app.url(:foo)
773
+ @app.uri_root = '/testing'
774
+ assert_equal "/testing/foo", @app.url(:foo)
775
+ @app.uri_root = '/testing/'
776
+ assert_equal "/testing/foo", @app.url(:foo)
777
+ @app.uri_root = 'testing/bar///'
778
+ assert_equal "/testing/bar/foo", @app.url(:foo)
779
+ end
780
+
781
+ should 'use uri_root with controllers' do
782
+ mock_app do
783
+ controller :foo do
784
+ get(:bar){ "bar" }
785
+ end
786
+ end
787
+ @app.uri_root = '/testing'
788
+ assert_equal "/testing/foo/bar", @app.url(:foo, :bar)
789
+ end
790
+
791
+ should 'use RACK_BASE_URI' do
792
+ mock_app do
793
+ get(:foo){ "foo" }
794
+ end
795
+ # Wish there was a side-effect free way to test this...
796
+ ENV['RACK_BASE_URI'] = '/'
797
+ assert_equal "/foo", @app.url(:foo)
798
+ ENV['RACK_BASE_URI'] = '/testing'
799
+ assert_equal "/testing/foo", @app.url(:foo)
800
+ ENV['RACK_BASE_URI'] = nil
801
+ end
802
+
803
+ should 'reset routes' do
804
+ mock_app do
805
+ get("/"){ "foo" }
806
+ reset_router!
807
+ end
808
+ get "/"
809
+ assert_equal 404, status
810
+ end
811
+
812
+ should "match params and format" do
813
+ app = mock_app do
814
+ get '/:id', :provides => [:json, :html] do |id, _|
815
+ id
816
+ end
817
+
818
+ get 'format/:id', :provides => [:json, :html] do |id, format|
819
+ format
820
+ end
821
+ end
822
+
823
+ get '/123.html'
824
+ assert_equal '123', body
825
+
826
+ get 'format/123.html'
827
+ assert_equal 'html', body
828
+ end
829
+
830
+
831
+ should 'respect priorities' do
832
+ route_order = []
833
+ mock_app do
834
+ get(:index, :priority => :normal) { route_order << :normal; pass }
835
+ get(:index, :priority => :low) { route_order << :low; "hello" }
836
+ get(:index, :priority => :high) { route_order << :high; pass }
837
+ end
838
+ get '/'
839
+ assert_equal [:high, :normal, :low], route_order
840
+ assert_equal "hello", body
841
+ end
842
+
843
+ should 'catch all after controllers' do
844
+ mock_app do
845
+ get(:index, :with => :slug, :priority => :low) { "catch all" }
846
+ controllers :contact do
847
+ get(:index) { "contact"}
848
+ end
849
+ end
850
+ get "/contact"
851
+ assert_equal "contact", body
852
+ get "/foo"
853
+ assert_equal "catch all", body
854
+ end
855
+
856
+ should 'allow optionals' do
857
+ mock_app do
858
+ get(:show, :map => "/stories/:type(/:category)") do
859
+ "#{params[:type]}/#{params[:category]}"
860
+ end
861
+ end
862
+ get "/stories/foo"
863
+ assert_equal "foo/", body
864
+ get "/stories/foo/bar"
865
+ assert_equal "foo/bar", body
866
+ end
867
+
868
+ should 'apply maps' do
869
+ mock_app do
870
+ controllers :admin do
871
+ get(:index, :map => "/"){ "index" }
872
+ get(:show, :with => :id, :map => "/show"){ "show #{params[:id]}" }
873
+ get(:edit, :map => "/edit/:id/product"){ "edit #{params[:id]}" }
874
+ get(:wacky, :map => "/wacky-:id-:product_id"){ "wacky #{params[:id]}-#{params[:product_id]}" }
875
+ end
876
+ end
877
+ get "/"
878
+ assert_equal "index", body
879
+ get @app.url(:admin, :index)
880
+ assert_equal "index", body
881
+ get "/show/1"
882
+ assert_equal "show 1", body
883
+ get "/edit/1/product"
884
+ assert_equal "edit 1", body
885
+ get "/wacky-1-2"
886
+ assert_equal "wacky 1-2", body
887
+ end
888
+
889
+ should 'apply maps when given path is kind of hash' do
890
+ mock_app do
891
+ controllers :admin do
892
+ get(:foobar, "/foo/bar"){ "foobar" }
893
+ end
894
+ end
895
+ get "/foo/bar"
896
+ assert_equal "foobar", body
897
+ end
898
+
899
+ should "apply parent to route" do
900
+ mock_app do
901
+ controllers :project do
902
+ get(:index, :parent => :user) { "index #{params[:user_id]}" }
903
+ get(:index, :parent => [:user, :section]) { "index #{params[:user_id]} #{params[:section_id]}" }
904
+ get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
905
+ get(:show, :with => :id, :parent => [:user, :product]) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
906
+ end
907
+ end
908
+ get "/user/1/project"
909
+ assert_equal "index 1", body
910
+ get "/user/1/section/3/project"
911
+ assert_equal "index 1 3", body
912
+ get "/user/1/project/edit/2"
913
+ assert_equal "edit 2 1", body
914
+ get "/user/1/product/2/project/show/3"
915
+ assert_equal "show 3 1 2", body
916
+ end
917
+
918
+ should "respect parent precedence: controllers parents go before route parents" do
919
+ mock_app do
920
+ controllers :project do
921
+ get(:index, :parent => :user) { "index #{params[:user_id]}" }
922
+ end
923
+
924
+ controllers :bar, :parent => :foo do
925
+ get(:index) { "index on foo #{params[:foo_id]} @ bar" }
926
+ get(:index, :parent => :baz) { "index on foo #{params[:foo_id]} @ baz #{params[:baz_id]} @ bar" }
927
+ end
928
+ end
929
+
930
+ get "/user/1/project"
931
+ assert_equal "index 1", body
932
+ get "/foo/1/bar"
933
+ assert_equal "index on foo 1 @ bar", body
934
+ get "/foo/1/baz/2/bar"
935
+ assert_equal "index on foo 1 @ baz 2 @ bar", body
936
+ end
937
+
938
+ should "keep a reference to the parent on the route" do
939
+ mock_app do
940
+ controllers :project do
941
+ get(:index, :parent => :user) { "index #{params[:user_id]}" }
942
+ get(:index, :parent => [:user, :section]) { "index #{params[:user_id]} #{params[:section_id]}" }
943
+ get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
944
+ get(:show, :with => :id, :parent => [:user, :product]) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
945
+ end
946
+
947
+ controllers :bar, :parent => :foo do
948
+ get(:index) { "index on foo/bar" }
949
+ get(:index, :parent => :baz) { "index on foo/baz/bar" }
950
+ end
951
+ end
952
+
953
+ # get "/user/1/project"
954
+ assert_equal :user, @app.routes[0].parent
955
+ # get "/user/1/section/3/project"
956
+ assert_equal [:user, :section], @app.routes[2].parent
957
+ # get "/user/1/project/edit/2"
958
+ assert_equal :user, @app.routes[4].parent
959
+ # get "/user/1/product/2/project/show/3"
960
+ assert_equal [:user, :product], @app.routes[6].parent
961
+ # get "/foo/1/bar"
962
+ assert_equal :foo, @app.routes[8].parent
963
+ # get "/foo/1/baz/2/bar"
964
+ assert_equal [:foo, :baz], @app.routes[10].parent
965
+ end
966
+
967
+ should "apply parent to controller" do
968
+ mock_app do
969
+ controller :project, :parent => :user do
970
+ get(:index) { "index #{params[:user_id]}"}
971
+ get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
972
+ get(:show, :with => :id, :parent => :product) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
973
+ end
974
+ end
975
+
976
+ user_project_url = "/user/1/project"
977
+ get user_project_url
978
+ assert_equal "index 1", body
979
+ assert_equal user_project_url, @app.url(:project, :index, :user_id => 1)
980
+
981
+ user_project_edit_url = "/user/1/project/edit/2"
982
+ get user_project_edit_url
983
+ assert_equal "edit 2 1", body
984
+ assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2)
985
+
986
+ user_product_project_url = "/user/1/product/2/project/show/3"
987
+ get user_product_project_url
988
+ assert_equal "show 3 1 2", body
989
+ assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3)
990
+ end
991
+
992
+ should "apply parent with shallowing to controller" do
993
+ mock_app do
994
+ controller :project do
995
+ parent :user
996
+ parent :shop, :optional => true
997
+ get(:index) { "index #{params[:user_id]} #{params[:shop_id]}" }
998
+ get(:edit, :with => :id) { "edit #{params[:id]} #{params[:user_id]} #{params[:shop_id]}" }
999
+ get(:show, :with => :id, :parent => :product) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]} #{params[:shop_id]}" }
1000
+ end
1001
+ end
1002
+
1003
+ assert_equal "/user/1/project", @app.url(:project, :index, :user_id => 1, :shop_id => nil)
1004
+ assert_equal "/user/1/shop/23/project", @app.url(:project, :index, :user_id => 1, :shop_id => 23)
1005
+
1006
+ user_project_url = "/user/1/project"
1007
+ get user_project_url
1008
+ assert_equal "index 1 ", body
1009
+ assert_equal user_project_url, @app.url(:project, :index, :user_id => 1)
1010
+
1011
+ user_project_edit_url = "/user/1/project/edit/2"
1012
+ get user_project_edit_url
1013
+ assert_equal "edit 2 1 ", body
1014
+ assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2)
1015
+
1016
+ user_product_project_url = "/user/1/product/2/project/show/3"
1017
+ get user_product_project_url
1018
+ assert_equal "show 3 1 2 ", body
1019
+ assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3)
1020
+
1021
+ user_project_url = "/user/1/shop/1/project"
1022
+ get user_project_url
1023
+ assert_equal "index 1 1", body
1024
+ assert_equal user_project_url, @app.url(:project, :index, :user_id => 1, :shop_id => 1)
1025
+
1026
+ user_project_edit_url = "/user/1/shop/1/project/edit/2"
1027
+ get user_project_edit_url
1028
+ assert_equal "edit 2 1 1", body
1029
+ assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2, :shop_id => 1)
1030
+
1031
+ user_product_project_url = "/user/1/shop/1/product/2/project/show/3"
1032
+ get user_product_project_url
1033
+ assert_equal "show 3 1 2 1", body
1034
+ assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3, :shop_id => 1)
1035
+ end
1036
+
1037
+ should "respect map in parents with shallowing" do
1038
+ mock_app do
1039
+ controller :project do
1040
+ parent :shop, :map => "/foo/bar"
1041
+ get(:index) { "index #{params[:shop_id]}" }
1042
+ end
1043
+ end
1044
+
1045
+ shop_project_url = "/foo/bar/1/project"
1046
+ get shop_project_url
1047
+ assert_equal "index 1", body
1048
+ assert_equal shop_project_url, @app.url(:project, :index, :shop_id => 1)
1049
+ end
1050
+
1051
+ should "use default values" do
1052
+ mock_app do
1053
+ controller :lang => :it do
1054
+ get(:index, :map => "/:lang") { "lang is #{params[:lang]}" }
1055
+ end
1056
+ # This is only for be sure that default values
1057
+ # work only for the given controller
1058
+ get(:foo, :map => "/foo") {}
1059
+ end
1060
+ assert_equal "/it", @app.url(:index)
1061
+ assert_equal "/foo", @app.url(:foo)
1062
+ get "/en"
1063
+ assert_equal "lang is en", body
1064
+ end
1065
+
1066
+ should "transitions to the next matching route on pass" do
1067
+ mock_app do
1068
+ get '/:foo' do
1069
+ pass
1070
+ 'Hello Foo'
1071
+ end
1072
+ get '/:bar' do
1073
+ 'Hello World'
1074
+ end
1075
+ end
1076
+
1077
+ get '/za'
1078
+ assert_equal 'Hello World', body
1079
+ end
1080
+
1081
+ should "filters by accept header" do
1082
+ mock_app do
1083
+ get '/foo', :provides => [:xml, :js] do
1084
+ request.env['HTTP_ACCEPT']
1085
+ end
1086
+ end
1087
+
1088
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1089
+ assert ok?
1090
+ assert_equal 'application/xml', body
1091
+ assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
1092
+
1093
+ get '/foo.xml'
1094
+ assert ok?
1095
+ assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
1096
+
1097
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript' }
1098
+ assert ok?
1099
+ assert_equal 'application/javascript', body
1100
+ assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
1101
+
1102
+ get '/foo.js'
1103
+ assert ok?
1104
+ assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
1105
+
1106
+ get '/foo', {}, { "HTTP_ACCEPT" => 'text/html' }
1107
+ assert_equal 406, status
1108
+ end
1109
+
1110
+ should "does not allow global provides" do
1111
+ mock_app do
1112
+ provides :xml
1113
+
1114
+ get("/foo"){ "Foo in #{content_type}" }
1115
+ get("/bar"){ "Bar in #{content_type}" }
1116
+ end
1117
+
1118
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1119
+ assert_equal 'Foo in xml', body
1120
+ get '/foo'
1121
+ assert_equal 'Foo in xml', body
1122
+
1123
+ get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1124
+ assert_equal 'Bar in html', body
1125
+ end
1126
+
1127
+ should "does not allow global provides in controller" do
1128
+ mock_app do
1129
+ controller :base do
1130
+ provides :xml
1131
+
1132
+ get(:foo, "/foo"){ "Foo in #{content_type}" }
1133
+ get(:bar, "/bar"){ "Bar in #{content_type}" }
1134
+ end
1135
+ end
1136
+
1137
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1138
+ assert_equal 'Foo in xml', body
1139
+ get '/foo'
1140
+ assert_equal 'Foo in xml', body
1141
+
1142
+ get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1143
+ assert_equal 'Bar in html', body
1144
+ end
1145
+
1146
+ should "map non named routes in controllers" do
1147
+ mock_app do
1148
+ controller :base do
1149
+ get("/foo") { "ok" }
1150
+ get("/bar") { "ok" }
1151
+ end
1152
+ end
1153
+
1154
+ get "/base/foo"
1155
+ assert ok?
1156
+ get "/base/bar"
1157
+ assert ok?
1158
+ end
1159
+
1160
+ should "set content_type to :html for both empty Accept as well as Accept text/html" do
1161
+ mock_app do
1162
+ provides :html
1163
+
1164
+ get("/foo"){ content_type.to_s }
1165
+ end
1166
+
1167
+ get '/foo', {}, {}
1168
+ assert_equal 'html', body
1169
+
1170
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'text/html' }
1171
+ assert_equal 'html', body
1172
+ end
1173
+
1174
+ should "set content_type to :html if Accept */*" do
1175
+ mock_app do
1176
+ get("/foo", :provides => [:html, :js]) { content_type.to_s }
1177
+ end
1178
+ get '/foo', {}, {}
1179
+ assert_equal 'html', body
1180
+
1181
+ get '/foo', {}, { 'HTTP_ACCEPT' => '*/*;q=0.5' }
1182
+ assert_equal 'html', body
1183
+ end
1184
+
1185
+ should "set content_type to :js if Accept includes both application/javascript and */*;q=0.5" do
1186
+ mock_app do
1187
+ get("/foo", :provides => [:html, :js]) { content_type.to_s }
1188
+ end
1189
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
1190
+ assert_equal 'js', body
1191
+ end
1192
+
1193
+ should "set content_type to :html if Accept */* and provides of :any" do
1194
+ mock_app do
1195
+ get("/foo", :provides => :any) { content_type.to_s }
1196
+ end
1197
+
1198
+ get '/foo', {}, { 'HTTP_ACCEPT' => '*/*' }
1199
+ assert_equal 'html', body
1200
+ end
1201
+
1202
+ should "set content_type to :js if Accept includes both application/javascript, */*;q=0.5 and provides of :any" do
1203
+ mock_app do
1204
+ get("/foo", :provides => :any) { content_type.to_s }
1205
+ end
1206
+
1207
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
1208
+ assert_equal 'js', body
1209
+ end
1210
+
1211
+ should 'allows custom route-conditions to be set via route options and halt' do
1212
+ protector = Module.new do
1213
+ def protect(*args)
1214
+ condition {
1215
+ unless authorize(params["user"], params["password"])
1216
+ halt 403, "go away"
1217
+ end
1218
+ }
1219
+ end
1220
+ end
1221
+
1222
+ mock_app do
1223
+ register protector
1224
+
1225
+ helpers do
1226
+ def authorize(username, password)
1227
+ username == "foo" && password == "bar"
1228
+ end
1229
+ end
1230
+
1231
+ get "/", :protect => true do
1232
+ "hey"
1233
+ end
1234
+ end
1235
+
1236
+ get "/"
1237
+ assert forbidden?
1238
+ assert_equal "go away", body
1239
+
1240
+ get "/", :user => "foo", :password => "bar"
1241
+ assert ok?
1242
+ assert_equal "hey", body
1243
+ end
1244
+
1245
+ should 'allows custom route-conditions to be set via route options using two routes' do
1246
+ protector = Module.new do
1247
+ def protect(*args)
1248
+ condition { authorize(params["user"], params["password"]) }
1249
+ end
1250
+ end
1251
+
1252
+ mock_app do
1253
+ register protector
1254
+
1255
+ helpers do
1256
+ def authorize(username, password)
1257
+ username == "foo" && password == "bar"
1258
+ end
1259
+ end
1260
+
1261
+ get "/", :protect => true do
1262
+ "hey"
1263
+ end
1264
+
1265
+ get "/" do
1266
+ "go away"
1267
+ end
1268
+ end
1269
+
1270
+ get "/"
1271
+ assert_equal "go away", body
1272
+
1273
+ get "/", :user => "foo", :password => "bar"
1274
+ assert ok?
1275
+ assert_equal "hey", body
1276
+ end
1277
+
1278
+ should "allow concise routing" do
1279
+ mock_app do
1280
+ get :index, ":id" do
1281
+ params[:id]
1282
+ end
1283
+
1284
+ get :map, "route/:id" do
1285
+ params[:id]
1286
+ end
1287
+ end
1288
+
1289
+ get "/123"
1290
+ assert_equal "123", body
1291
+
1292
+ get "/route/123"
1293
+ assert_equal "123", body
1294
+ end
1295
+
1296
+ should "support halting with 404 and message" do
1297
+ mock_app do
1298
+ controller do
1299
+ get :index do
1300
+ halt 404, "not found"
1301
+ end
1302
+ end
1303
+ end
1304
+
1305
+ get "/"
1306
+ assert_equal 404, status
1307
+ assert_equal "not found", body
1308
+ end
1309
+
1310
+ should "allow passing & halting in before filters" do
1311
+ mock_app do
1312
+ controller do
1313
+ before { env['QUERY_STRING'] == 'secret' or pass }
1314
+ get :index do
1315
+ "secret index"
1316
+ end
1317
+ end
1318
+
1319
+ controller do
1320
+ before { env['QUERY_STRING'] == 'halt' and halt 401, 'go away!' }
1321
+ get :index do
1322
+ "index"
1323
+ end
1324
+ end
1325
+ end
1326
+
1327
+ get "/?secret"
1328
+ assert_equal "secret index", body
1329
+
1330
+ get "/?halt"
1331
+ assert_equal "go away!", body
1332
+ assert_equal 401, status
1333
+
1334
+ get "/"
1335
+ assert_equal "index", body
1336
+ end
1337
+
1338
+ should 'scope filters in the given controller' do
1339
+ mock_app do
1340
+ before { @global = 'global' }
1341
+ after { @global = nil }
1342
+
1343
+ controller :foo do
1344
+ before { @foo = :foo }
1345
+ after { @foo = nil }
1346
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
1347
+ end
1348
+
1349
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
1350
+
1351
+ controller :bar do
1352
+ before { @bar = :bar }
1353
+ after { @bar = nil }
1354
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
1355
+ end
1356
+ end
1357
+
1358
+ get "/bar"
1359
+ assert_equal "bar global", body
1360
+
1361
+ get "/foo"
1362
+ assert_equal "foo global", body
1363
+
1364
+ get "/"
1365
+ assert_equal "global", body
1366
+ end
1367
+
1368
+ should 'works with optionals params' do
1369
+ mock_app do
1370
+ get("/foo(/:bar)") { params[:bar] }
1371
+ end
1372
+
1373
+ get "/foo/bar"
1374
+ assert_equal "bar", body
1375
+
1376
+ get "/foo"
1377
+ assert_equal "", body
1378
+ end
1379
+
1380
+ should 'work with multiple dashed params' do
1381
+ mock_app do
1382
+ get "/route/:foo/:bar/:baz", :provides => :html do
1383
+ "#{params[:foo]};#{params[:bar]};#{params[:baz]}"
1384
+ end
1385
+ end
1386
+
1387
+ get "/route/foo/bar/baz"
1388
+ assert_equal 'foo;bar;baz', body
1389
+
1390
+ get "/route/foo/bar-whatever/baz"
1391
+ assert_equal 'foo;bar-whatever;baz', body
1392
+ end
1393
+
1394
+ should 'work with arbitrary params' do
1395
+ mock_app do
1396
+ get(:testing) { params[:foo] }
1397
+ end
1398
+
1399
+ url = @app.url(:testing, :foo => 'bar')
1400
+ assert_equal "/testing?foo=bar", url
1401
+ get url
1402
+ assert_equal "bar", body
1403
+ end
1404
+
1405
+ should 'ignore nil params' do
1406
+ mock_app do
1407
+ get(:testing, :provides => [:html, :json]) do
1408
+ end
1409
+ end
1410
+ assert_equal '/testing.html', @app.url(:testing, :format => :html)
1411
+ assert_equal '/testing', @app.url(:testing, :format => nil)
1412
+ end
1413
+
1414
+ should 'be able to access params in a before filter' do
1415
+ username_from_before_filter = nil
1416
+
1417
+ mock_app do
1418
+ before do
1419
+ username_from_before_filter = params[:username]
1420
+ end
1421
+
1422
+ get :users, :with => :username do
1423
+ end
1424
+ end
1425
+ get '/users/josh'
1426
+ assert_equal 'josh', username_from_before_filter
1427
+ end
1428
+
1429
+ should "be able to access params normally when a before filter is specified" do
1430
+ mock_app do
1431
+ before { }
1432
+ get :index do
1433
+ params.inspect
1434
+ end
1435
+ end
1436
+ get '/?test=what'
1437
+ assert_equal '{"test"=>"what"}', body
1438
+ end
1439
+
1440
+ should 'work with controller and arbitrary params' do
1441
+ mock_app do
1442
+ get(:testing) { params[:foo] }
1443
+ controller :test1 do
1444
+ get(:url1) { params[:foo] }
1445
+ get(:url2, :provides => [:html, :json]) { params[:foo] }
1446
+ end
1447
+ end
1448
+
1449
+ url = @app.url(:test1, :url1, :foo => 'bar1')
1450
+ assert_equal "/test1/url1?foo=bar1", url
1451
+ get url
1452
+ assert_equal "bar1", body
1453
+
1454
+ url = @app.url(:test1, :url2, :foo => 'bar2')
1455
+ assert_equal "/test1/url2?foo=bar2", url
1456
+ get url
1457
+ assert_equal "bar2", body
1458
+ end
1459
+
1460
+ should "parse two routes with the same path but different http verbs" do
1461
+ mock_app do
1462
+ get(:index) { "This is the get index" }
1463
+ post(:index) { "This is the post index" }
1464
+ end
1465
+ get "/"
1466
+ assert_equal "This is the get index", body
1467
+ post "/"
1468
+ assert_equal "This is the post index", body
1469
+ end
1470
+
1471
+ should "use optionals params" do
1472
+ mock_app do
1473
+ get(:index, :map => "/(:foo(/:bar))") { "#{params[:foo]}-#{params[:bar]}" }
1474
+ end
1475
+ get "/foo"
1476
+ assert_equal "foo-", body
1477
+ get "/foo/bar"
1478
+ assert_equal "foo-bar", body
1479
+ end
1480
+
1481
+ should "parse two routes with the same path but different http verbs and provides" do
1482
+ mock_app do
1483
+ get(:index, :provides => [:html, :json]) { "This is the get index.#{content_type}" }
1484
+ post(:index, :provides => [:html, :json]) { "This is the post index.#{content_type}" }
1485
+ end
1486
+ get "/"
1487
+ assert_equal "This is the get index.html", body
1488
+ post "/"
1489
+ assert_equal "This is the post index.html", body
1490
+ get "/.json"
1491
+ assert_equal "This is the get index.json", body
1492
+ get "/.js"
1493
+ assert_equal 404, status
1494
+ post "/.json"
1495
+ assert_equal "This is the post index.json", body
1496
+ post "/.js"
1497
+ assert_equal 404, status
1498
+ end
1499
+
1500
+ should "allow controller level mapping" do
1501
+ mock_app do
1502
+ controller :map => "controller-:id" do
1503
+ get(:url3) { "#{params[:id]}" }
1504
+ get(:url4, :map => 'test-:id2') { "#{params[:id]}, #{params[:id2]}" }
1505
+ end
1506
+ end
1507
+
1508
+ url = @app.url(:url3, :id => 1)
1509
+ assert_equal "/controller-1/url3", url
1510
+ get url
1511
+ assert_equal "1", body
1512
+
1513
+ url = @app.url(:url4, 1, 2)
1514
+ assert_equal "/controller-1/test-2", url
1515
+ get url
1516
+ assert_equal "1, 2", body
1517
+ end
1518
+
1519
+ should "replace name of named controller with mapping path" do
1520
+ mock_app do
1521
+ controller :ugly, :map => "/pretty/:id" do
1522
+ get(:url3) { "#{params[:id]}" }
1523
+ get(:url4, :map => 'test-:id2') { "#{params[:id]}, #{params[:id2]}" }
1524
+ end
1525
+ controller :voldemort, :map => "" do
1526
+ get(:url5) { "okay" }
1527
+ end
1528
+ end
1529
+
1530
+ url = @app.url(:ugly, :url3, :id => 1)
1531
+ assert_equal "/pretty/1/url3", url
1532
+ get url
1533
+ assert_equal "1", body
1534
+
1535
+ url = @app.url(:ugly, :url4, 3, 5)
1536
+ assert_equal "/pretty/3/test-5", url
1537
+ get url
1538
+ assert_equal "3, 5", body
1539
+
1540
+ url = @app.url(:voldemort, :url5)
1541
+ assert_equal "/url5", url
1542
+ get url
1543
+ assert_equal 'okay', body
1544
+ end
1545
+
1546
+ should 'use absolute and relative maps' do
1547
+ mock_app do
1548
+ controller :one do
1549
+ parent :three
1550
+ get :index, :map => 'one' do; end
1551
+ get :index2, :map => '/one' do; end
1552
+ end
1553
+
1554
+ controller :two, :map => 'two' do
1555
+ parent :three
1556
+ get :index, :map => 'two' do; end
1557
+ get :index2, :map => '/two', :with => :id do; end
1558
+ end
1559
+ end
1560
+ assert_equal "/three/three_id/one", @app.url(:one, :index, 'three_id')
1561
+ assert_equal "/one", @app.url(:one, :index2)
1562
+ assert_equal "/two/three/three_id/two", @app.url(:two, :index, 'three_id')
1563
+ assert_equal "/two/four_id", @app.url(:two, :index2, 'four_id')
1564
+ end
1565
+
1566
+ should "work with params and parent options" do
1567
+ mock_app do
1568
+ controller :test2, :parent => :parent1, :parent1_id => 1 do
1569
+ get(:url3) { params[:foo] }
1570
+ get(:url4, :with => :with1) { params[:foo] }
1571
+ get(:url5, :with => :with2, :provides => [:html]) { params[:foo] }
1572
+ end
1573
+ end
1574
+
1575
+ url = @app.url(:test2, :url3, :foo => 'bar3')
1576
+ assert_equal "/parent1/1/test2/url3?foo=bar3", url
1577
+ get url
1578
+ assert_equal "bar3", body
1579
+
1580
+ url = @app.url(:test2, :url4, :with1 => 'awith1', :foo => 'bar4')
1581
+ assert_equal "/parent1/1/test2/url4/awith1?foo=bar4", url
1582
+ get url
1583
+ assert_equal "bar4", body
1584
+
1585
+ url = @app.url(:test2, :url5, :with2 => 'awith1', :foo => 'bar5')
1586
+ assert_equal "/parent1/1/test2/url5/awith1?foo=bar5", url
1587
+ get url
1588
+ assert_equal "bar5", body
1589
+ end
1590
+
1591
+ should "parse params without explicit provides for every matching route" do
1592
+ mock_app do
1593
+ get(:index, :map => "/foos/:bar") { "get bar = #{params[:bar]}" }
1594
+ post :create, :map => "/foos/:bar", :provides => [:html, :js] do
1595
+ "post bar = #{params[:bar]}"
1596
+ end
1597
+ end
1598
+
1599
+ get "/foos/hello"
1600
+ assert_equal "get bar = hello", body
1601
+ post "/foos/hello"
1602
+ assert_equal "post bar = hello", body
1603
+ post "/foos/hello.js"
1604
+ assert_equal "post bar = hello", body
1605
+ end
1606
+
1607
+ should "properly route to first foo with two similar routes" do
1608
+ mock_app do
1609
+ controllers do
1610
+ get('/foo/') { "this is foo" }
1611
+ get(:show, :map => "/foo/:bar/:id") { "/foo/#{params[:bar]}/#{params[:id]}" }
1612
+ end
1613
+ end
1614
+ get "/foo"
1615
+ assert_equal "this is foo", body
1616
+ get "/foo/"
1617
+ assert_equal "this is foo", body
1618
+ get '/foo/5/10'
1619
+ assert_equal "/foo/5/10", body
1620
+ end
1621
+
1622
+ should "index routes should be optional when nested" do
1623
+ mock_app do
1624
+ controller '/users', :provides => [:json] do
1625
+ get '/' do
1626
+ "foo"
1627
+ end
1628
+ end
1629
+ end
1630
+ get "/users.json"
1631
+ assert_equal "foo", body
1632
+ end
1633
+
1634
+ should "use provides as conditional" do
1635
+ mock_app do
1636
+ provides :json
1637
+ get "/" do
1638
+ "foo"
1639
+ end
1640
+ end
1641
+ get "/.json"
1642
+ assert_equal "foo", body
1643
+ end
1644
+
1645
+ should_eventually "reset provides for routes that didn't use it" do
1646
+ mock_app do
1647
+ get('/foo', :provides => :js){}
1648
+ get('/bar'){}
1649
+ end
1650
+ get '/foo'
1651
+ assert ok?
1652
+ get '/foo.js'
1653
+ assert ok?
1654
+ get '/bar'
1655
+ assert ok?
1656
+ get '/bar.js'
1657
+ assert_equal 404, status
1658
+ end
1659
+
1660
+ should "pass controller conditions to each route" do
1661
+ counter = 0
1662
+
1663
+ mock_app do
1664
+ self.class.send(:define_method, :increment!) do |*args|
1665
+ condition { counter += 1 }
1666
+ end
1667
+
1668
+ controller :posts, :conditions => {:increment! => true} do
1669
+ get("/foo") { "foo" }
1670
+ get("/bar") { "bar" }
1671
+ end
1672
+
1673
+ end
1674
+
1675
+ get "/posts/foo"
1676
+ get "/posts/bar"
1677
+ assert_equal 2, counter
1678
+ end
1679
+
1680
+ should "allow controller conditions to be overridden" do
1681
+ counter = 0
1682
+
1683
+ mock_app do
1684
+ self.class.send(:define_method, :increment!) do |increment|
1685
+ condition { counter += 1 } if increment
1686
+ end
1687
+
1688
+ controller :posts, :conditions => {:increment! => true} do
1689
+ get("/foo") { "foo" }
1690
+ get("/bar", :increment! => false) { "bar" }
1691
+ end
1692
+
1693
+ end
1694
+
1695
+ get "/posts/foo"
1696
+ get "/posts/bar"
1697
+ assert_equal 1, counter
1698
+ end
1699
+
1700
+ should "parse params with class level provides" do
1701
+ mock_app do
1702
+ controllers :posts, :provides => [:html, :js] do
1703
+ post(:create, :map => "/foo/:bar/:baz/:id") {
1704
+ "POST CREATE #{params[:bar]} - #{params[:baz]} - #{params[:id]}"
1705
+ }
1706
+ end
1707
+ controllers :topics, :provides => [:js, :html] do
1708
+ get(:show, :map => "/foo/:bar/:baz/:id") { render "topics/show" }
1709
+ post(:create, :map => "/foo/:bar/:baz") { "TOPICS CREATE #{params[:bar]} - #{params[:baz]}" }
1710
+ end
1711
+ end
1712
+ post "/foo/bar/baz.js"
1713
+ assert_equal "TOPICS CREATE bar - baz", body, "should parse params with explicit .js"
1714
+ post @app.url(:topics, :create, :format => :js, :bar => 'bar', :baz => 'baz')
1715
+ assert_equal "TOPICS CREATE bar - baz", body, "should parse params from generated url"
1716
+ post "/foo/bar/baz/5.js"
1717
+ assert_equal "POST CREATE bar - baz - 5", body
1718
+ post @app.url(:posts, :create, :format => :js, :bar => 'bar', :baz => 'baz', :id => 5)
1719
+ assert_equal "POST CREATE bar - baz - 5", body
1720
+ end
1721
+
1722
+ should "parse params properly with inline provides" do
1723
+ mock_app do
1724
+ controllers :posts do
1725
+ post(:create, :map => "/foo/:bar/:baz/:id", :provides => [:html, :js]) {
1726
+ "POST CREATE #{params[:bar]} - #{params[:baz]} - #{params[:id]}"
1727
+ }
1728
+ end
1729
+ controllers :topics do
1730
+ get(:show, :map => "/foo/:bar/:baz/:id", :provides => [:html, :js]) { render "topics/show" }
1731
+ post(:create, :map => "/foo/:bar/:baz", :provides => [:html, :js]) { "TOPICS CREATE #{params[:bar]} - #{params[:baz]}" }
1732
+ end
1733
+ end
1734
+ post @app.url(:topics, :create, :format => :js, :bar => 'bar', :baz => 'baz')
1735
+ assert_equal "TOPICS CREATE bar - baz", body, "should properly post to topics create action"
1736
+ post @app.url(:posts, :create, :format => :js, :bar => 'bar', :baz => 'baz', :id => 5)
1737
+ assert_equal "POST CREATE bar - baz - 5", body, "should properly post to create action"
1738
+ end
1739
+
1740
+ should "have overideable format" do
1741
+ ::Rack::Mime::MIME_TYPES[".other"] = "text/html"
1742
+ mock_app do
1743
+ before do
1744
+ params[:format] ||= :other
1745
+ end
1746
+ get("/format_test", :provides => [:html, :other]){ content_type.to_s }
1747
+ end
1748
+ get "/format_test"
1749
+ assert_equal "other", body
1750
+ ::Rack::Mime::MIME_TYPES.delete('.other')
1751
+ end
1752
+
1753
+ should 'invokes handlers registered with ::error when raised' do
1754
+ mock_app do
1755
+ set :raise_errors, false
1756
+ error(FooError) { 'Foo!' }
1757
+ get '/' do
1758
+ raise FooError
1759
+ end
1760
+ end
1761
+ get '/'
1762
+ assert_equal 500, status
1763
+ assert_equal 'Foo!', body
1764
+ end
1765
+
1766
+ should 'have MethodOverride middleware' do
1767
+ mock_app do
1768
+ put('/') { 'okay' }
1769
+ end
1770
+ assert @app.method_override?
1771
+ post '/', {'_method'=>'PUT'}, {}
1772
+ assert_equal 200, status
1773
+ assert_equal 'okay', body
1774
+ end
1775
+
1776
+ should 'return value from params' do
1777
+ mock_app do
1778
+ get("/foo/:bar"){ raise "'bar' should be a string" unless params[:bar].kind_of? String}
1779
+ end
1780
+ get "/foo/50"
1781
+ assert ok?
1782
+ end
1783
+
1784
+ should 'have MethodOverride middleware with more options' do
1785
+ mock_app do
1786
+ put('/hi', :provides => [:json]) { 'hi' }
1787
+ end
1788
+ post '/hi', {'_method'=>'PUT'}
1789
+ assert_equal 200, status
1790
+ assert_equal 'hi', body
1791
+ post '/hi.json', {'_method'=>'PUT'}
1792
+ assert_equal 200, status
1793
+ assert_equal 'hi', body
1794
+ post '/hi.json'
1795
+ assert_equal 405, status
1796
+ end
1797
+
1798
+ should 'parse nested params' do
1799
+ mock_app do
1800
+ get(:index) { "%s %s" % [params[:account][:name], params[:account][:surname]] }
1801
+ end
1802
+ get "/?account[name]=foo&account[surname]=bar"
1803
+ assert_equal 'foo bar', body
1804
+ get @app.url(:index, "account[name]" => "foo", "account[surname]" => "bar")
1805
+ assert_equal 'foo bar', body
1806
+ end
1807
+
1808
+ should 'render sinatra NotFound page' do
1809
+ mock_app { set :environment, :development }
1810
+ get "/"
1811
+ assert_equal 404, status
1812
+ assert_match %r{(Sinatra doesn&rsquo;t know this ditty.|<h1>Not Found</h1>)}, body
1813
+ end
1814
+
1815
+ should 'render a custom NotFound page' do
1816
+ mock_app do
1817
+ error(Sinatra::NotFound) { "not found" }
1818
+ end
1819
+ get "/"
1820
+ assert_equal 404, status
1821
+ assert_match /not found/, body
1822
+ end
1823
+
1824
+ should 'render a custom 404 page using not_found' do
1825
+ mock_app do
1826
+ not_found { "custom 404 not found" }
1827
+ end
1828
+ get "/"
1829
+ assert_equal 404, status
1830
+ assert_equal "custom 404 not found", body
1831
+ end
1832
+
1833
+ should 'render a custom error page using error method' do
1834
+ skip
1835
+ mock_app do
1836
+ error(404) { "custom 404 error" }
1837
+ end
1838
+ get "/"
1839
+ assert_equal 404, status
1840
+ assert_equal "custom 404 error", body
1841
+ end
1842
+
1843
+ should 'render a custom 403 page' do
1844
+ mock_app do
1845
+ error(403) { "custom 403 not found" }
1846
+ get("/") { status 403 }
1847
+ end
1848
+ get "/"
1849
+ assert_equal 403, status
1850
+ assert_equal "custom 403 not found", body
1851
+ end
1852
+
1853
+ should 'recognize paths' do
1854
+ mock_app do
1855
+ controller :foo do
1856
+ get(:bar, :map => "/my/:id/custom-route") { }
1857
+ end
1858
+ get(:simple, :map => "/simple/:id") { }
1859
+ get(:with_format, :with => :id, :provides => :js) { }
1860
+ end
1861
+ assert_equal [:foo_bar, { :id => "fantastic" }], @app.recognize_path(@app.url(:foo, :bar, :id => :fantastic))
1862
+ assert_equal [:foo_bar, { :id => "18" }], @app.recognize_path(@app.url(:foo, :bar, :id => 18))
1863
+ assert_equal [:simple, { :id => "bar" }], @app.recognize_path(@app.url(:simple, :id => "bar"))
1864
+ assert_equal [:simple, { :id => "true" }], @app.recognize_path(@app.url(:simple, :id => true))
1865
+ assert_equal [:simple, { :id => "9" }], @app.recognize_path(@app.url(:simple, :id => 9))
1866
+ assert_equal [:with_format, { :id => "bar", :format => "js" }], @app.recognize_path(@app.url(:with_format, :id => "bar", :format => :js))
1867
+ assert_equal [:with_format, { :id => "true", :format => "js" }], @app.recognize_path(@app.url(:with_format, :id => true, :format => "js"))
1868
+ assert_equal [:with_format, { :id => "9", :format => "js" }], @app.recognize_path(@app.url(:with_format, :id => 9, :format => :js))
1869
+ end
1870
+
1871
+ should 'have current_path' do
1872
+ mock_app do
1873
+ controller :foo do
1874
+ get(:index) { current_path }
1875
+ get :bar, :map => "/paginate/:page" do
1876
+ current_path
1877
+ end
1878
+ get(:after) { current_path }
1879
+ end
1880
+ end
1881
+ get "/paginate/10"
1882
+ assert_equal "/paginate/10", body
1883
+ get "/foo/after"
1884
+ assert_equal "/foo/after", body
1885
+ get "/foo"
1886
+ assert_equal "/foo", body
1887
+ end
1888
+
1889
+ should 'accept :map and :parent' do
1890
+ mock_app do
1891
+ controller :posts do
1892
+ get :show, :parent => :users, :map => "posts/:id" do
1893
+ "#{params[:user_id]}-#{params[:id]}"
1894
+ end
1895
+ end
1896
+ end
1897
+ get '/users/123/posts/321'
1898
+ assert_equal "123-321", body
1899
+ end
1900
+
1901
+ should 'change params in current_path' do
1902
+ mock_app do
1903
+ get :index, :map => "/paginate/:page" do
1904
+ current_path(:page => 66)
1905
+ end
1906
+ end
1907
+ get @app.url(:index, :page => 10)
1908
+ assert_equal "/paginate/66", body
1909
+ end
1910
+
1911
+ should 'not route get :users, :with => :id to /users//' do
1912
+ mock_app do
1913
+ get(:users, :with => :id) { 'boo' }
1914
+ end
1915
+ get '/users//'
1916
+ assert_equal 404, status
1917
+ end
1918
+ end