howl-router 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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