tennpipes-base 3.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.rdoc +294 -0
  4. data/Rakefile +1 -0
  5. data/bin/tennpipes +8 -0
  6. data/lib/tennpipes-base.rb +196 -0
  7. data/lib/tennpipes-base/application.rb +175 -0
  8. data/lib/tennpipes-base/application/application_setup.rb +202 -0
  9. data/lib/tennpipes-base/application/authenticity_token.rb +25 -0
  10. data/lib/tennpipes-base/application/flash.rb +229 -0
  11. data/lib/tennpipes-base/application/params_protection.rb +129 -0
  12. data/lib/tennpipes-base/application/routing.rb +1002 -0
  13. data/lib/tennpipes-base/application/show_exceptions.rb +50 -0
  14. data/lib/tennpipes-base/caller.rb +53 -0
  15. data/lib/tennpipes-base/cli/adapter.rb +33 -0
  16. data/lib/tennpipes-base/cli/base.rb +105 -0
  17. data/lib/tennpipes-base/cli/console.rb +20 -0
  18. data/lib/tennpipes-base/cli/launcher.rb +103 -0
  19. data/lib/tennpipes-base/cli/rake.rb +50 -0
  20. data/lib/tennpipes-base/cli/rake_tasks.rb +72 -0
  21. data/lib/tennpipes-base/command.rb +38 -0
  22. data/lib/tennpipes-base/ext/sinatra.rb +29 -0
  23. data/lib/tennpipes-base/filter.rb +52 -0
  24. data/lib/tennpipes-base/images/404.png +0 -0
  25. data/lib/tennpipes-base/images/500.png +0 -0
  26. data/lib/tennpipes-base/loader.rb +202 -0
  27. data/lib/tennpipes-base/logger.rb +492 -0
  28. data/lib/tennpipes-base/module.rb +58 -0
  29. data/lib/tennpipes-base/mounter.rb +308 -0
  30. data/lib/tennpipes-base/path_router.rb +119 -0
  31. data/lib/tennpipes-base/path_router/compiler.rb +110 -0
  32. data/lib/tennpipes-base/path_router/error_handler.rb +8 -0
  33. data/lib/tennpipes-base/path_router/matcher.rb +123 -0
  34. data/lib/tennpipes-base/path_router/route.rb +169 -0
  35. data/lib/tennpipes-base/reloader.rb +309 -0
  36. data/lib/tennpipes-base/reloader/rack.rb +26 -0
  37. data/lib/tennpipes-base/reloader/storage.rb +55 -0
  38. data/lib/tennpipes-base/router.rb +98 -0
  39. data/lib/tennpipes-base/server.rb +119 -0
  40. data/lib/tennpipes-base/tasks.rb +21 -0
  41. data/lib/tennpipes-base/version.rb +20 -0
  42. data/lib/tennpipes-base/version.rb~ +20 -0
  43. data/test/fixtures/app_gem/Gemfile +4 -0
  44. data/test/fixtures/app_gem/app/app.rb +3 -0
  45. data/test/fixtures/app_gem/app_gem.gemspec +17 -0
  46. data/test/fixtures/app_gem/lib/app_gem.rb +7 -0
  47. data/test/fixtures/app_gem/lib/app_gem/version.rb +3 -0
  48. data/test/fixtures/apps/complex.rb +32 -0
  49. data/test/fixtures/apps/demo_app.rb +7 -0
  50. data/test/fixtures/apps/demo_demo.rb +7 -0
  51. data/test/fixtures/apps/demo_project/api/app.rb +7 -0
  52. data/test/fixtures/apps/demo_project/api/lib/api_lib.rb +3 -0
  53. data/test/fixtures/apps/demo_project/app.rb +7 -0
  54. data/test/fixtures/apps/external_apps/fake_lib.rb +1 -0
  55. data/test/fixtures/apps/external_apps/fake_root.rb +2 -0
  56. data/test/fixtures/apps/helpers/class_methods_helpers.rb +4 -0
  57. data/test/fixtures/apps/helpers/instance_methods_helpers.rb +4 -0
  58. data/test/fixtures/apps/helpers/support.rb +1 -0
  59. data/test/fixtures/apps/helpers/system_helpers.rb +8 -0
  60. data/test/fixtures/apps/kiq.rb +3 -0
  61. data/test/fixtures/apps/lib/myklass.rb +2 -0
  62. data/test/fixtures/apps/lib/myklass/mysubklass.rb +4 -0
  63. data/test/fixtures/apps/models/child.rb +2 -0
  64. data/test/fixtures/apps/models/parent.rb +5 -0
  65. data/test/fixtures/apps/mountable_apps/rack_apps.rb +15 -0
  66. data/test/fixtures/apps/mountable_apps/static.html +1 -0
  67. data/test/fixtures/apps/precompiled_app.rb +19 -0
  68. data/test/fixtures/apps/simple.rb +32 -0
  69. data/test/fixtures/apps/static.rb +10 -0
  70. data/test/fixtures/apps/system.rb +13 -0
  71. data/test/fixtures/apps/system_class_methods_demo.rb +7 -0
  72. data/test/fixtures/apps/system_instance_methods_demo.rb +7 -0
  73. data/test/fixtures/dependencies/a.rb +9 -0
  74. data/test/fixtures/dependencies/b.rb +4 -0
  75. data/test/fixtures/dependencies/c.rb +1 -0
  76. data/test/fixtures/dependencies/circular/e.rb +13 -0
  77. data/test/fixtures/dependencies/circular/f.rb +2 -0
  78. data/test/fixtures/dependencies/circular/g.rb +2 -0
  79. data/test/fixtures/dependencies/d.rb +4 -0
  80. data/test/fixtures/reloadable_apps/external/app/app.rb +6 -0
  81. data/test/fixtures/reloadable_apps/external/app/controllers/base.rb +6 -0
  82. data/test/fixtures/reloadable_apps/main/app.rb +10 -0
  83. data/test/helper.rb +30 -0
  84. data/test/test_application.rb +185 -0
  85. data/test/test_core.rb +93 -0
  86. data/test/test_csrf_protection.rb +208 -0
  87. data/test/test_dependencies.rb +57 -0
  88. data/test/test_filters.rb +389 -0
  89. data/test/test_flash.rb +168 -0
  90. data/test/test_locale.rb +21 -0
  91. data/test/test_logger.rb +295 -0
  92. data/test/test_mounter.rb +302 -0
  93. data/test/test_params_protection.rb +195 -0
  94. data/test/test_reloader_complex.rb +74 -0
  95. data/test/test_reloader_external.rb +21 -0
  96. data/test/test_reloader_simple.rb +101 -0
  97. data/test/test_reloader_system.rb +113 -0
  98. data/test/test_restful_routing.rb +33 -0
  99. data/test/test_router.rb +281 -0
  100. data/test/test_routing.rb +2328 -0
  101. metadata +301 -0
@@ -0,0 +1,2328 @@
1
+ #encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/helper')
3
+
4
+ class FooError < RuntimeError; end
5
+
6
+ class RegexpLookAlike
7
+ # RegexpLookAlike#to_s, RegexpLookAlike#names and MatchData#names must be defined.
8
+ class MatchData
9
+ def captures
10
+ ["this", "is", "a", "test"]
11
+ end
12
+
13
+ def names
14
+ ["one", "two", "three", "four"]
15
+ end
16
+ end
17
+
18
+ def names
19
+ ["one", "two", "three", "four"]
20
+ end
21
+
22
+ def to_s
23
+ "/this/is/a/test/"
24
+ end
25
+
26
+ def match(string)
27
+ ::RegexpLookAlike::MatchData.new if string == "/this/is/a/test/"
28
+ end
29
+ end
30
+
31
+ describe "Routing" do
32
+ before do
33
+ Tennpipes.clear!
34
+ ENV['RACK_BASE_URI'] = nil
35
+ end
36
+
37
+ it 'should serve static files with simple cache control' do
38
+ mock_app do
39
+ set :static_cache_control, :public
40
+ set :public_folder, File.dirname(__FILE__)
41
+ end
42
+ get "/#{File.basename(__FILE__)}"
43
+ assert headers.has_key?('Cache-Control')
44
+ assert_equal headers['Cache-Control'], 'public'
45
+ end # static simple
46
+
47
+ it 'should serve static files with cache control and max_age' do
48
+ mock_app do
49
+ set :static_cache_control, [:public, :must_revalidate, {:max_age => 300}]
50
+ set :public_folder, File.dirname(__FILE__)
51
+ end
52
+ get "/#{File.basename(__FILE__)}"
53
+ assert headers.has_key?('Cache-Control')
54
+ assert_equal headers['Cache-Control'], 'public, must-revalidate, max-age=300'
55
+ end # static max_age
56
+
57
+ it 'should render static files with custom status via options' do
58
+ mock_app do
59
+ set :static, true
60
+ set :public_folder, File.dirname(__FILE__)
61
+
62
+ post '/*' do
63
+ static!(:status => params[:status])
64
+ end
65
+ end
66
+
67
+ post "/#{File.basename(__FILE__)}?status=422"
68
+ assert_equal response.status, 422
69
+ assert_equal File.size(__FILE__).to_s, response['Content-Length']
70
+ assert response.headers.include?('Last-Modified')
71
+ end
72
+
73
+ it 'should ignore trailing delimiters for basic route' do
74
+ mock_app do
75
+ get("/foo"){ "okey" }
76
+ get(:test) { "tester" }
77
+ end
78
+ get "/foo"
79
+ assert_equal "okey", body
80
+ get "/foo/"
81
+ assert_equal "okey", body
82
+ get "/test"
83
+ assert_equal "tester", body
84
+ get "/test/"
85
+ assert_equal "tester", body
86
+ end
87
+
88
+ it 'should fail with unrecognized route exception when not found' do
89
+ mock_app do
90
+ get(:index){ "okey" }
91
+ end
92
+ get @app.url_for(:index)
93
+ assert_equal "okey", body
94
+ assert_raises(Tennpipes::Routing::UnrecognizedException) {
95
+ get @app.url_for(:fake)
96
+ }
97
+ end
98
+
99
+ it 'should fail with unrecognized route exception when namespace is invalid' do
100
+ mock_app do
101
+ controller :foo_bar do
102
+ get(:index){ "okey" }
103
+ get(:test_baz){ "okey" }
104
+ end
105
+ end
106
+ assert_equal "/foo_bar", @app.url_for(:foo_bar, :index)
107
+ assert_raises(Tennpipes::Routing::UnrecognizedException) {
108
+ get @app.url_for(:foo, :bar, :index)
109
+ }
110
+ assert_raises(Tennpipes::Routing::UnrecognizedException) {
111
+ get @app.url_for(:foo, :bar_index)
112
+ }
113
+ assert_equal "/foo_bar/test_baz", @app.url_for(:foo_bar, :test_baz)
114
+ assert_raises(Tennpipes::Routing::UnrecognizedException) {
115
+ get @app.url_for(:foo_bar, :test, :baz)
116
+ }
117
+ assert_raises(Tennpipes::Routing::UnrecognizedException) {
118
+ get @app.url_for(:foo, :bar_test, :baz)
119
+ }
120
+ assert_raises(Tennpipes::Routing::UnrecognizedException) {
121
+ get @app.url_for(:foo, :bar_test_baz)
122
+ }
123
+ end
124
+
125
+ it 'should accept regexp routes' do
126
+ mock_app do
127
+ get(%r./fob|/baz.) { "regexp" }
128
+ get("/foo") { "str" }
129
+ get %r./([0-9]+)/. do |num|
130
+ "Your lucky number: #{num} #{params[:captures].first}"
131
+ end
132
+ get %r./page/([0-9]+)|/. do |num|
133
+ "My lucky number: #{num} #{params[:captures].first}"
134
+ end
135
+ end
136
+ get "/foo"
137
+ assert_equal "str", body
138
+ get "/fob"
139
+ assert_equal "regexp", body
140
+ get "/baz"
141
+ assert_equal "regexp", body
142
+ get "/321/"
143
+ assert_equal "Your lucky number: 321 321", body
144
+ get "/page/99"
145
+ assert_equal "My lucky number: 99 99", body
146
+ end
147
+
148
+ it 'should accept regexp routes with generate with :generate_with' do
149
+ mock_app do
150
+ get(%r{/fob|/baz}, :name => :foo, :generate_with => '/fob') { "regexp" }
151
+ end
152
+ assert_equal "/fob", @app.url(:foo)
153
+ end
154
+
155
+ it 'should parse routes with question marks' do
156
+ mock_app do
157
+ get("/foo/?"){ "okey" }
158
+ post('/unauthenticated/?') { "no access" }
159
+ end
160
+ get "/foo"
161
+ assert_equal "okey", body
162
+ get "/foo/"
163
+ assert_equal "okey", body
164
+ post "/unauthenticated"
165
+ assert_equal "no access", body
166
+ post "/unauthenticated/"
167
+ assert_equal "no access", body
168
+ end
169
+
170
+ it 'should parse routes that are encoded' do
171
+ mock_app do
172
+ get('/щч') { 'success!' }
173
+ end
174
+ get(URI.escape('/щч'))
175
+ assert_equal 'success!', body
176
+ end
177
+
178
+ it 'should parse routes that include encoded slash' do
179
+ mock_app do
180
+ get('/:drive_alias/:path', :path => /.*/){
181
+ "Show #{params[:drive_alias]} and #{params[:path]}"
182
+ }
183
+ end
184
+ get("/drive%2Ffoo/some/path")
185
+ assert_equal "Show drive/foo and some/path", body
186
+ end
187
+
188
+ it 'should encode params using UTF-8' do
189
+ mock_app do
190
+ get('/:foo') { params[:foo].encoding.name }
191
+ end
192
+ get '/bar'
193
+ assert_equal 'UTF-8', body
194
+ end
195
+
196
+ it 'should match correctly similar paths' do
197
+ mock_app do
198
+ get("/my/:foo_id"){ params[:foo_id] }
199
+ get("/my/:bar_id/bar"){ params[:bar_id] }
200
+ end
201
+ get "/my/1"
202
+ assert_equal "1", body
203
+ get "/my/2/bar"
204
+ assert_equal "2", body
205
+ end
206
+
207
+ it 'should match user agents' do
208
+ app = mock_app do
209
+ get("/main", :agent => /IE/){ "hello IE" }
210
+ get("/main"){ "hello" }
211
+ end
212
+ get "/main"
213
+ assert_equal "hello", body
214
+ get "/main", {}, {'HTTP_USER_AGENT' => 'This is IE'}
215
+ assert_equal "hello IE", body
216
+ end
217
+
218
+ it 'should use regex for parts of a route' do
219
+ app = mock_app do
220
+ get("/main/:id", :id => /\d+/){ "hello #{params[:id]}" }
221
+ end
222
+ get "/main/123"
223
+ assert_equal "hello 123", body
224
+ get "/main/asd"
225
+ assert_equal 404, status
226
+ end
227
+
228
+ it 'should parse params when use regex for parts of a route' do
229
+ mock_app do
230
+ post :index, :with => [:foo, :bar], :bar => /.+/ do
231
+ "show #{params[:foo]}"
232
+ end
233
+
234
+ get :index, :map => '/mystuff/:a_id/boing/:boing_id' do
235
+ "show #{params[:a_id]} and #{params[:boing_id]}"
236
+ end
237
+ end
238
+ get "/mystuff/5/boing/2"
239
+ assert_equal "show 5 and 2", body
240
+ end
241
+
242
+ it 'should not generate overlapping head urls' do
243
+ app = mock_app do
244
+ get("/main"){ "hello" }
245
+ post("/main"){ "hello" }
246
+ end
247
+ assert_equal 3, app.routes.size, "should generate GET, HEAD and PUT"
248
+ assert_equal "GET", app.routes[0].request_methods.first
249
+ assert_equal "HEAD", app.routes[1].request_methods.first
250
+ assert_equal "POST", app.routes[2].request_methods.first
251
+ end
252
+
253
+ it 'should generate basic urls' do
254
+ mock_app do
255
+ get(:foo){ "/foo" }
256
+ get(:foo, :with => :id){ |id| "/foo/#{id}" }
257
+ get([:foo, :id]){ |id| "/foo/#{id}" }
258
+ get(:hash, :with => :id){ url(:hash, :id => 1) }
259
+ get(:anchor) { url(:anchor, :anchor => 'comments') }
260
+ get(:fragment) { url(:anchor, :fragment => 'comments') }
261
+ get(:fragment2) { url(:anchor, :fragment => :comments) }
262
+ get([:hash, :id]){ url(:hash, :id => 1) }
263
+ get(:array, :with => :id){ url(:array, 23) }
264
+ get([:array, :id]){ url(:array, 23) }
265
+ get(:hash_with_extra, :with => :id){ url(:hash_with_extra, :id => 1, :query => 'string') }
266
+ get([:hash_with_extra, :id]){ url(:hash_with_extra, :id => 1, :query => 'string') }
267
+ get(:array_with_extra, :with => :id){ url(:array_with_extra, 23, :query => 'string') }
268
+ get([:array_with_extra, :id]){ url(:array_with_extra, 23, :query => 'string') }
269
+ get("/old-bar/:id"){ params[:id] }
270
+ post(:mix, :map => "/mix-bar/:id"){ params[:id] }
271
+ get(:mix, :map => "/mix-bar/:id"){ params[:id] }
272
+ get(:foo, '', :with => :id){ |id| "/#{id}" }
273
+ post(:foo, '', :with => :id){ |id| "/#{id}" }
274
+ delete(:drugs, :with => [:id, 'destroy']){ |id| "/drugs/#{id}/destroy" }
275
+ delete(:drugs, '', :with => [:id, 'destroy']){ |id| "/#{id}/destroy" }
276
+ get(:splatter, "/splatter/*/*"){ |a, b| url(:splatter, :splat => ["123", "456"]) }
277
+ end
278
+ get "/foo"
279
+ assert_equal "/foo", body
280
+ get "/foo/123"
281
+ assert_equal "/foo/123", body
282
+ get "/hash/2"
283
+ assert_equal "/hash/1", body
284
+ get "/anchor"
285
+ assert_equal "/anchor#comments", body
286
+ get "/fragment"
287
+ assert_equal "/anchor#comments", body
288
+ get "/fragment2"
289
+ assert_equal "/anchor#comments", body
290
+ get "/array/23"
291
+ assert_equal "/array/23", body
292
+ get "/hash_with_extra/1"
293
+ assert_equal "/hash_with_extra/1?query=string", body
294
+ get "/array_with_extra/23"
295
+ assert_equal "/array_with_extra/23?query=string", body
296
+ get "/old-bar/3"
297
+ assert_equal "3", body
298
+ post "/mix-bar/4"
299
+ assert_equal "4", body
300
+ get "/mix-bar/4"
301
+ assert_equal "4", body
302
+ get "/123"
303
+ assert_equal "/123", body
304
+ post "/123"
305
+ assert_equal "/123", body
306
+ delete "/drugs/123/destroy"
307
+ assert_equal "/drugs/123/destroy", body
308
+ delete "/123/destroy"
309
+ assert_equal "/123/destroy", body
310
+ get "/splatter/123/456"
311
+ assert_equal "/splatter/123/456", body
312
+ end
313
+
314
+ it 'should generate url with format' do
315
+ mock_app do
316
+ get(:a, :provides => :any){ url(:a, :format => :json) }
317
+ get(:b, :provides => :js){ url(:b, :format => :js) }
318
+ get(:c, :provides => [:js, :json]){ url(:c, :format => :json) }
319
+ get(:d, :provides => [:html, :js]){ url(:d, :format => :js, :foo => :bar) }
320
+ end
321
+ get "/a.js"
322
+ assert_equal "/a.json", body
323
+ get "/b.js"
324
+ assert_equal "/b.js", body
325
+ get "/b.ru"
326
+ assert_equal 404, status
327
+ get "/c.js"
328
+ assert_equal "/c.json", body
329
+ get "/c.json"
330
+ assert_equal "/c.json", body
331
+ get "/c.ru"
332
+ assert_equal 404, status
333
+ get "/d"
334
+ assert_equal "/d.js?foo=bar", body
335
+ get "/d.js"
336
+ assert_equal "/d.js?foo=bar", body
337
+ get "/e.xml"
338
+ assert_equal 404, status
339
+ end
340
+
341
+ it 'should generate absolute urls' do
342
+ mock_app do
343
+ get(:hash, :with => :id){ absolute_url(:hash, :id => 1) }
344
+ end
345
+ get "/hash/2"
346
+ assert_equal "http://example.org/hash/1", body
347
+ get "https://example.org/hash/2"
348
+ assert_equal "https://example.org/hash/1", body
349
+ end
350
+
351
+ it 'should generate absolute urls from stringified keys' do
352
+ mock_app do
353
+ get(:hash, with: :id) { absolute_url(:hash, "id" => 1) }
354
+ end
355
+ get "/hash/2"
356
+ assert_equal "http://example.org/hash/1", body
357
+ end
358
+
359
+ it 'should generate proper absolute urls for mounted apps' do
360
+ class Test < Tennpipes::Application
361
+ get :foo do
362
+ absolute_url(:foo, :id => 1)
363
+ end
364
+ end
365
+ Tennpipes.mount("Test").to("/test")
366
+ @app = Tennpipes.application
367
+ get('/test/foo')
368
+ assert_equal 'http://example.org/test/foo?id=1', body
369
+ end
370
+
371
+ it 'should rebase simple string urls to app uri_root' do
372
+ mock_app do
373
+ set :uri_root, '/app'
374
+ get(:a){ url('/foo') }
375
+ get(:b){ url('bar') }
376
+ get(:c){ absolute_url('/foo') }
377
+ get(:d, :map => '/d/e/f'){ absolute_url('bar') }
378
+ end
379
+ get "/a"
380
+ assert_equal "/app/foo", body
381
+ get "/b"
382
+ assert_equal "bar", body
383
+ get "/c"
384
+ assert_equal "http://example.org/app/foo", body
385
+ get "/d/e/f"
386
+ assert_equal "http://example.org/app/d/e/bar", body
387
+ end
388
+
389
+ it 'should allow regex url with format' do
390
+ mock_app do
391
+ get(/.*/, :provides => :any) { "regexp" }
392
+ end
393
+ get "/anything"
394
+ assert_equal "regexp", body
395
+ end
396
+
397
+ it 'should use tennpipes url method' do
398
+ mock_app do
399
+ end
400
+
401
+ assert_equal @app.method(:url).owner, Tennpipes::Routing::ClassMethods
402
+ end
403
+
404
+ it 'should work correctly with sinatra redirects' do
405
+ mock_app do
406
+ get(:index) { redirect url(:index) }
407
+ get(:google) { redirect "http://google.com" }
408
+ get("/foo") { redirect "/bar" }
409
+ get("/bar") { "Bar" }
410
+ end
411
+
412
+ get "/"
413
+ assert_equal "http://example.org/", headers['Location']
414
+ get "/google"
415
+ assert_equal "http://google.com", headers['Location']
416
+ get "/foo"
417
+ assert_equal "http://example.org/bar", headers['Location']
418
+ end
419
+
420
+ it 'should return 406 on Accept-Headers it does not provide' do
421
+ mock_app do
422
+ get(:a, :provides => [:html, :js]){ content_type }
423
+ end
424
+
425
+ get "/a", {}, {"HTTP_ACCEPT" => "application/yaml"}
426
+ assert_equal 406, status
427
+ end
428
+
429
+ it 'should return 406 on file extensions it does not provide and flag is set' do
430
+ mock_app do
431
+ enable :treat_format_as_accept
432
+ get(:a, :provides => [:html, :js]){ content_type }
433
+ end
434
+
435
+ get "/a.xml", {}, {}
436
+ assert_equal 406, status
437
+ end
438
+
439
+ it 'should return 404 on file extensions it does not provide and flag is not set' do
440
+ mock_app do
441
+ get(:a, :provides => [:html, :js]){ content_type }
442
+ end
443
+
444
+ get "/a.xml", {}, {}
445
+ assert_equal 404, status
446
+ end
447
+
448
+ it 'should not set content_type to :html if Accept */* and html not in provides' do
449
+ mock_app do
450
+ get("/foo", :provides => [:json, :xml]) { content_type.to_s }
451
+ end
452
+
453
+ get '/foo', {}, { 'HTTP_ACCEPT' => '*/*;q=0.5' }
454
+ assert_equal 'json', body
455
+ end
456
+
457
+ it 'should set content_type to :json if Accept contains */*' do
458
+ mock_app do
459
+ get("/foo", :provides => [:json]) { content_type.to_s }
460
+ end
461
+
462
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' }
463
+ assert_equal 'json', body
464
+ end
465
+
466
+ it 'should set and get content_type' do
467
+ mock_app do
468
+ get("/foo"){ content_type(:json); content_type.to_s }
469
+ end
470
+ get "/foo"
471
+ assert_equal 'application/json', content_type
472
+ assert_equal 'json', body
473
+ end
474
+
475
+ it 'should send the appropriate number of params' do
476
+ mock_app do
477
+ get('/id/:user_id', :provides => [:json]) { |user_id, format| user_id}
478
+ end
479
+ get '/id/5.json'
480
+ assert_equal '5', body
481
+ end
482
+
483
+ it 'should allow "." in param values' do
484
+ mock_app do
485
+ get('/id/:email', :provides => [:json]) { |email, format| [email, format] * '/' }
486
+ end
487
+ get '/id/foo@bar.com.json'
488
+ assert_equal 'foo@bar.com/json', body
489
+ end
490
+
491
+ it 'should set correct content_type for Accept not equal to */* even if */* also provided' do
492
+ mock_app do
493
+ get("/foo", :provides => [:html, :js, :xml]) { content_type.to_s }
494
+ end
495
+
496
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
497
+ assert_equal 'js', body
498
+ end
499
+
500
+ it 'should return the first content type in provides if accept header is empty' do
501
+ mock_app do
502
+ get(:a, :provides => [:js]){ content_type.to_s }
503
+ end
504
+
505
+ get "/a", {}, {}
506
+ assert_equal "js", body
507
+ end
508
+
509
+ it 'should not default to HTML if HTML is not provided and no type is given' do
510
+ mock_app do
511
+ get(:a, :provides => [:js]){ content_type }
512
+ end
513
+
514
+ get "/a", {}, {}
515
+ assert_equal "application/javascript;charset=utf-8", content_type
516
+ end
517
+
518
+ it 'should not match routes if url_format and http_accept is provided but not included' do
519
+ mock_app do
520
+ get(:a, :provides => [:js, :html]){ content_type }
521
+ end
522
+
523
+ get "/a.xml", {}, {"HTTP_ACCEPT" => "text/html"}
524
+ assert_equal 404, status
525
+ end
526
+
527
+ it 'should generate routes for format simple' do
528
+ mock_app do
529
+ get(:foo, :provides => [:html, :rss]) { render :haml, "Test" }
530
+ end
531
+ get "/foo"
532
+ assert_equal "Test\n", body
533
+ get "/foo.rss"
534
+ assert_equal "Test\n", body
535
+ end
536
+
537
+ it 'should inject the controller name into the request' do
538
+ mock_app do
539
+ controller :posts do
540
+ get(:index) { request.controller }
541
+ controller :mini do
542
+ get(:index) { request.controller }
543
+ end
544
+ end
545
+ end
546
+ get "/posts"
547
+ assert_equal "posts", body
548
+ get "/mini"
549
+ assert_equal "mini", body
550
+ end
551
+
552
+ it 'should inject the action name into the request' do
553
+ mock_app do
554
+ controller :posts do
555
+ get('/omnomnom(/:id)?') { request.action.inspect }
556
+ controller :mini do
557
+ get([:a, :b, :c]) { request.action.inspect }
558
+ end
559
+ end
560
+ end
561
+ get "/posts/omnomnom"
562
+ assert_equal "\"/omnomnom(/:id)?\"", body
563
+ get "/mini/a/b/c"
564
+ assert_equal ":a", body
565
+ end
566
+
567
+ it 'should support not_found' do
568
+ mock_app do
569
+ not_found { 'whatever' }
570
+
571
+ get :index, :map => "/" do
572
+ 'index'
573
+ end
574
+ end
575
+ get '/wrong'
576
+ assert_equal 404, status
577
+ assert_equal 'whatever', body
578
+ get '/'
579
+ assert_equal 'index', body
580
+ assert_equal 200, status
581
+ end
582
+
583
+ it 'should inject the route into the request' do
584
+ mock_app do
585
+ controller :posts do
586
+ get(:index) { request.route_obj.name.to_s }
587
+ end
588
+ end
589
+ get "/posts"
590
+ assert_equal "posts index", body
591
+ end
592
+
593
+ it 'should preserve the format if you set it manually' do
594
+ mock_app do
595
+ before do
596
+ params[:format] = "json"
597
+ end
598
+
599
+ get "test", :provides => [:html, :json] do
600
+ content_type.inspect
601
+ end
602
+ end
603
+ get "/test"
604
+ assert_equal ":json", body
605
+ get "/test.html"
606
+ assert_equal ":json", body
607
+ get "/test.php"
608
+ assert_equal ":json", body
609
+ end
610
+
611
+ it 'should correctly accept "." in the route' do
612
+ mock_app do
613
+ get "test.php", :provides => [:html, :json] do
614
+ content_type.inspect
615
+ end
616
+ end
617
+ get "/test.php"
618
+ assert_equal ":html", body
619
+ get "/test.php.json"
620
+ assert_equal ":json", body
621
+ end
622
+
623
+ it 'should correctly accept priority of format' do
624
+ mock_app do
625
+ get "test.php", :provides => [:html, :json, :xml] do
626
+ content_type.inspect
627
+ end
628
+ end
629
+
630
+ get "/test.php"
631
+ assert_equal ":html", body
632
+ get "/test.php", {}, { 'HTTP_ACCEPT' => 'application/xml' }
633
+ assert_equal ":xml", body
634
+ get "/test.php?format=json", { 'HTTP_ACCEPT' => 'application/xml' }
635
+ assert_equal ":json", body
636
+ get "/test.php.json?format=html", { 'HTTP_ACCEPT' => 'application/xml' }
637
+ assert_equal ":json", body
638
+ end
639
+
640
+ it 'should generate routes for format with controller' do
641
+ mock_app do
642
+ controller :posts do
643
+ get(:index, :provides => [:html, :rss, :atom, :js]) { render :haml, "Index.#{content_type}" }
644
+ get(:show, :with => :id, :provides => [:html, :rss, :atom]) { render :haml, "Show.#{content_type}" }
645
+ end
646
+ end
647
+ get "/posts"
648
+ assert_equal "Index.html\n", body
649
+ get "/posts.rss"
650
+ assert_equal "Index.rss\n", body
651
+ get "/posts.atom"
652
+ assert_equal "Index.atom\n", body
653
+ get "/posts.js"
654
+ assert_equal "Index.js\n", body
655
+ get "/posts/show/5"
656
+ assert_equal "Show.html\n", body
657
+ get "/posts/show/5.rss"
658
+ assert_equal "Show.rss\n", body
659
+ get "/posts/show/10.atom"
660
+ assert_equal "Show.atom\n", body
661
+ end
662
+
663
+ it 'should map routes' do
664
+ mock_app do
665
+ get(:bar){ "bar" }
666
+ end
667
+ get "/bar"
668
+ assert_equal "bar", body
669
+ assert_equal "/bar", @app.url(:bar)
670
+ end
671
+
672
+ it 'should remove index from path' do
673
+ mock_app do
674
+ get(:index){ "index" }
675
+ get("/accounts/index"){ "accounts" }
676
+ end
677
+ get "/"
678
+ assert_equal "index", body
679
+ assert_equal "/", @app.url(:index)
680
+ get "/accounts/index"
681
+ assert_equal "accounts", body
682
+ end
683
+
684
+ it 'should remove index from path with params' do
685
+ mock_app do
686
+ get(:index, :with => :name){ "index with #{params[:name]}" }
687
+ end
688
+ get "/bobby"
689
+ assert_equal "index with bobby", body
690
+ assert_equal "/john", @app.url(:index, :name => "john")
691
+ end
692
+
693
+ it 'should parse named params' do
694
+ mock_app do
695
+ get(:print, :with => :id){ "Im #{params[:id]}" }
696
+ end
697
+ get "/print/9"
698
+ assert_equal "Im 9", body
699
+ assert_equal "/print/9", @app.url(:print, :id => 9)
700
+ end
701
+
702
+ it 'should 405 on wrong request_method' do
703
+ mock_app do
704
+ post('/bar'){ "bar" }
705
+ end
706
+ get "/bar"
707
+ assert_equal 405, status
708
+ end
709
+
710
+ it 'should respond to' do
711
+ mock_app do
712
+ get(:a, :provides => :js){ "js" }
713
+ get(:b, :provides => :any){ "any" }
714
+ get(:c, :provides => [:js, :json]){ "js,json" }
715
+ get(:d, :provides => [:html, :js]){ "html,js"}
716
+ end
717
+ get "/a"
718
+ assert_equal 200, status
719
+ assert_equal "js", body
720
+ get "/a.js"
721
+ assert_equal "js", body
722
+ get "/b"
723
+ assert_equal "any", body
724
+ # TODO randomly fails in minitest :(
725
+ # assert_raises(RuntimeError) { get "/b.foo" }
726
+ get "/c"
727
+ assert_equal 200, status
728
+ assert_equal "js,json", body
729
+ get "/c.js"
730
+ assert_equal "js,json", body
731
+ get "/c.json"
732
+ assert_equal "js,json", body
733
+ get "/d"
734
+ assert_equal "html,js", body
735
+ get "/d.js"
736
+ assert_equal "html,js", body
737
+ end
738
+
739
+ it 'should respond_to and set content_type' do
740
+ Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
741
+ mock_app do
742
+ get :a, :provides => :any do
743
+ case content_type
744
+ when :js then "js"
745
+ when :json then "json"
746
+ when :foo then "foo"
747
+ when :html then "html"
748
+ end
749
+ end
750
+ end
751
+ get "/a.js"
752
+ assert_equal "js", body
753
+ assert_equal 'application/javascript;charset=utf-8', response["Content-Type"]
754
+ get "/a.json"
755
+ assert_equal "json", body
756
+ assert_equal 'application/json', response["Content-Type"]
757
+ get "/a.foo"
758
+ assert_equal "foo", body
759
+ assert_equal 'application/foo;charset=utf-8', response["Content-Type"]
760
+ get "/a"
761
+ assert_equal "html", body
762
+ assert_equal 'text/html;charset=utf-8', response["Content-Type"]
763
+ end
764
+
765
+ it 'should use controllers' do
766
+ mock_app do
767
+ controller "/admin" do
768
+ get("/"){ "index" }
769
+ get("/show/:id"){ "show #{params[:id]}" }
770
+ end
771
+ end
772
+ get "/admin"
773
+ assert_equal "index", body
774
+ get "/admin/show/1"
775
+ assert_equal "show 1", body
776
+ end
777
+
778
+ it 'should use named controllers' do
779
+ mock_app do
780
+ controller :admin do
781
+ get(:index, :with => :id){ params[:id] }
782
+ get(:show, :with => :id){ "show #{params[:id]}" }
783
+ end
784
+ controllers :foo, :bar do
785
+ get(:index){ "foo_bar_index" }
786
+ end
787
+ end
788
+ get "/admin/1"
789
+ assert_equal "1", body
790
+ get "/admin/show/1"
791
+ assert_equal "show 1", body
792
+ assert_equal "/admin/1", @app.url(:admin, :index, :id => 1)
793
+ assert_equal "/admin/show/1", @app.url(:admin, :show, :id => 1)
794
+ get "/foo/bar"
795
+ assert_equal "foo_bar_index", body
796
+ end
797
+
798
+ it 'should use map and with' do
799
+ mock_app do
800
+ get :index, :map => '/bugs', :with => :id do
801
+ params[:id]
802
+ end
803
+ end
804
+ get '/bugs/4'
805
+ assert_equal '4', body
806
+ assert_equal "/bugs/4", @app.url(:index, :id => 4)
807
+ end
808
+
809
+ it 'should ignore trailing delimiters within a named controller' do
810
+ mock_app do
811
+ controller :posts do
812
+ get(:index, :provides => [:html, :js]){ "index" }
813
+ get(:new) { "new" }
814
+ get(:show, :with => :id){ "show #{params[:id]}" }
815
+ end
816
+ end
817
+ get "/posts"
818
+ assert_equal "index", body
819
+ get "/posts/"
820
+ assert_equal "index", body
821
+ get "/posts.js"
822
+ assert_equal "index", body
823
+ get "/posts.js/"
824
+ assert_equal "index", body
825
+ get "/posts/new"
826
+ assert_equal "new", body
827
+ get "/posts/new/"
828
+ assert_equal "new", body
829
+ end
830
+
831
+ it 'should ignore trailing delimiters within a named controller for unnamed actions' do
832
+ mock_app do
833
+ controller :accounts do
834
+ get("/") { "account_index" }
835
+ get("/new") { "new" }
836
+ end
837
+ controller :votes do
838
+ get("/") { "vote_index" }
839
+ end
840
+ end
841
+ get "/accounts"
842
+ assert_equal "account_index", body
843
+ get "/accounts/"
844
+ assert_equal "account_index", body
845
+ get "/accounts/new"
846
+ assert_equal "new", body
847
+ get "/accounts/new/"
848
+ assert_equal "new", body
849
+ get "/votes"
850
+ assert_equal "vote_index", body
851
+ get "/votes/"
852
+ assert_equal "vote_index", body
853
+ end
854
+
855
+ it 'should use named controllers with array routes' do
856
+ mock_app do
857
+ controller :admin do
858
+ get(:index){ "index" }
859
+ get(:show, :with => :id){ "show #{params[:id]}" }
860
+ end
861
+ controllers :foo, :bar do
862
+ get(:index){ "foo_bar_index" }
863
+ end
864
+ end
865
+ get "/admin"
866
+ assert_equal "index", body
867
+ get "/admin/show/1"
868
+ assert_equal "show 1", body
869
+ assert_equal "/admin", @app.url(:admin, :index)
870
+ assert_equal "/admin/show/1", @app.url(:admin, :show, :id => 1)
871
+ get "/foo/bar"
872
+ assert_equal "foo_bar_index", body
873
+ end
874
+
875
+ it 'should support a reindex action and remove index inside controller' do
876
+ mock_app do
877
+ controller :posts do
878
+ get(:index){ "index" }
879
+ get(:reindex){ "reindex" }
880
+ end
881
+ end
882
+ get "/posts"
883
+ assert_equal "index", body
884
+ get "/posts/reindex"
885
+ assert_equal "/posts/reindex", @app.url(:posts, :reindex)
886
+ assert_equal "reindex", body
887
+ end
888
+
889
+ it 'should use uri_root' do
890
+ mock_app do
891
+ get(:foo){ "foo" }
892
+ end
893
+ @app.uri_root = '/'
894
+ assert_equal "/foo", @app.url(:foo)
895
+ @app.uri_root = '/testing'
896
+ assert_equal "/testing/foo", @app.url(:foo)
897
+ @app.uri_root = '/testing/'
898
+ assert_equal "/testing/foo", @app.url(:foo)
899
+ @app.uri_root = 'testing/bar///'
900
+ assert_equal "/testing/bar/foo", @app.url(:foo)
901
+ end
902
+
903
+ it 'should use uri_root with controllers' do
904
+ mock_app do
905
+ controller :foo do
906
+ get(:bar){ "bar" }
907
+ end
908
+ end
909
+ @app.uri_root = '/testing'
910
+ assert_equal "/testing/foo/bar", @app.url(:foo, :bar)
911
+ end
912
+
913
+ it 'should use RACK_BASE_URI' do
914
+ mock_app do
915
+ get(:foo){ "foo" }
916
+ end
917
+ # Wish there was a side-effect free way to test this...
918
+ ENV['RACK_BASE_URI'] = '/'
919
+ assert_equal "/foo", @app.url(:foo)
920
+ ENV['RACK_BASE_URI'] = '/testing'
921
+ assert_equal "/testing/foo", @app.url(:foo)
922
+ ENV['RACK_BASE_URI'] = nil
923
+ end
924
+
925
+ it 'should use uri_root and RACK_BASE_URI' do
926
+ mock_app do
927
+ controller :foo do
928
+ get(:bar){ "bar" }
929
+ end
930
+ end
931
+ ENV['RACK_BASE_URI'] = '/base'
932
+ @app.uri_root = 'testing'
933
+ assert_equal '/base/testing/foo/bar', @app.url(:foo, :bar)
934
+ ENV['RACK_BASE_URI'] = nil
935
+ end
936
+
937
+ it 'should reset routes' do
938
+ mock_app do
939
+ get("/"){ "foo" }
940
+ reset_router!
941
+ end
942
+ get "/"
943
+ assert_equal 404, status
944
+ end
945
+
946
+ it 'should match params and format' do
947
+ app = mock_app do
948
+ get '/:id', :provides => [:json, :html] do |id, _|
949
+ id
950
+ end
951
+
952
+ get 'format/:id', :provides => [:json, :html] do |id, format|
953
+ format
954
+ end
955
+ end
956
+
957
+ get '/123.html'
958
+ assert_equal '123', body
959
+
960
+ get 'format/123.html'
961
+ assert_equal 'html', body
962
+ end
963
+
964
+
965
+ it 'should respect priorities' do
966
+ route_order = []
967
+ mock_app do
968
+ get(:index, :priority => :normal) { route_order << :normal; pass }
969
+ get(:index, :priority => :low) { route_order << :low; "hello" }
970
+ get(:index, :priority => :high) { route_order << :high; pass }
971
+ end
972
+ get '/'
973
+ assert_equal [:high, :normal, :low], route_order
974
+ assert_equal "hello", body
975
+ end
976
+
977
+ it 'should set the params correctly even if using prioritized routes' do
978
+ mock_app do
979
+ get("*__sinatra__/:image.png"){}
980
+ get "/:primary/:secondary", :priority => :low do
981
+ "#{params[:primary]} #{params[:secondary]}"
982
+ end
983
+ end
984
+ get "/abc/def"
985
+ assert_equal "abc def", body
986
+ end
987
+
988
+ it 'should catch all after controllers' do
989
+ mock_app do
990
+ get(:index, :with => :slug, :priority => :low) { "catch all" }
991
+ controllers :contact do
992
+ get(:index) { "contact"}
993
+ end
994
+ end
995
+ get "/contact"
996
+ assert_equal "contact", body
997
+ get "/foo"
998
+ assert_equal "catch all", body
999
+ end
1000
+
1001
+ it 'should allow optionals' do
1002
+ mock_app do
1003
+ get(:show, :map => "/stories/:type(/:category)?") do
1004
+ "#{params[:type]}/#{params[:category]}"
1005
+ end
1006
+ end
1007
+ get "/stories/foo"
1008
+ assert_equal "foo/", body
1009
+ get "/stories/foo/bar"
1010
+ assert_equal "foo/bar", body
1011
+ end
1012
+
1013
+ it 'should apply maps' do
1014
+ mock_app do
1015
+ controllers :admin do
1016
+ get(:index, :map => "/"){ "index" }
1017
+ get(:show, :with => :id, :map => "/show"){ "show #{params[:id]}" }
1018
+ get(:edit, :map => "/edit/:id/product"){ "edit #{params[:id]}" }
1019
+ get(:wacky, :map => "/wacky-:id-:product_id"){ "wacky #{params[:id]}-#{params[:product_id]}" }
1020
+ end
1021
+ end
1022
+ get "/"
1023
+ assert_equal "index", body
1024
+ get @app.url(:admin, :index)
1025
+ assert_equal "index", body
1026
+ get "/show/1"
1027
+ assert_equal "show 1", body
1028
+ get "/edit/1/product"
1029
+ assert_equal "edit 1", body
1030
+ get "/wacky-1-2"
1031
+ assert_equal "wacky 1-2", body
1032
+ end
1033
+
1034
+ it 'should apply maps when given path is kind of hash' do
1035
+ mock_app do
1036
+ controllers :admin do
1037
+ get(:foobar, "/foo/bar"){ "foobar" }
1038
+ end
1039
+ end
1040
+ get "/foo/bar"
1041
+ assert_equal "foobar", body
1042
+ end
1043
+
1044
+ it 'should apply parent to route' do
1045
+ mock_app do
1046
+ controllers :project do
1047
+ get(:index, :parent => :user) { "index #{params[:user_id]}" }
1048
+ get(:index, :parent => [:user, :section]) { "index #{params[:user_id]} #{params[:section_id]}" }
1049
+ get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
1050
+ get(:show, :with => :id, :parent => [:user, :product]) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
1051
+ end
1052
+ end
1053
+ get "/user/1/project"
1054
+ assert_equal "index 1", body
1055
+ get "/user/1/section/3/project"
1056
+ assert_equal "index 1 3", body
1057
+ get "/user/1/project/edit/2"
1058
+ assert_equal "edit 2 1", body
1059
+ get "/user/1/product/2/project/show/3"
1060
+ assert_equal "show 3 1 2", body
1061
+ end
1062
+
1063
+ it 'should respect parent precedence: controllers parents go before route parents' do
1064
+ mock_app do
1065
+ controllers :project do
1066
+ get(:index, :parent => :user) { "index #{params[:user_id]}" }
1067
+ end
1068
+
1069
+ controllers :bar, :parent => :foo do
1070
+ get(:index) { "index on foo #{params[:foo_id]} @ bar" }
1071
+ get(:index, :parent => :baz) { "index on foo #{params[:foo_id]} @ baz #{params[:baz_id]} @ bar" }
1072
+ end
1073
+ end
1074
+
1075
+ get "/user/1/project"
1076
+ assert_equal "index 1", body
1077
+ get "/foo/1/bar"
1078
+ assert_equal "index on foo 1 @ bar", body
1079
+ get "/foo/1/baz/2/bar"
1080
+ assert_equal "index on foo 1 @ baz 2 @ bar", body
1081
+ end
1082
+
1083
+ it 'should keep a reference to the parent on the route' do
1084
+ mock_app do
1085
+ controllers :project do
1086
+ get(:index, :parent => :user) { "index #{params[:user_id]}" }
1087
+ get(:index, :parent => [:user, :section]) { "index #{params[:user_id]} #{params[:section_id]}" }
1088
+ get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
1089
+ get(:show, :with => :id, :parent => [:user, :product]) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
1090
+ end
1091
+
1092
+ controllers :bar, :parent => :foo do
1093
+ get(:index) { "index on foo/bar" }
1094
+ get(:index, :parent => :baz) { "index on foo/baz/bar" }
1095
+ end
1096
+ end
1097
+
1098
+ # get "/user/1/project"
1099
+ assert_equal :user, @app.routes[0].parent
1100
+ # get "/user/1/section/3/project"
1101
+ assert_equal [:user, :section], @app.routes[2].parent
1102
+ # get "/user/1/project/edit/2"
1103
+ assert_equal :user, @app.routes[4].parent
1104
+ # get "/user/1/product/2/project/show/3"
1105
+ assert_equal [:user, :product], @app.routes[6].parent
1106
+ # get "/foo/1/bar"
1107
+ assert_equal :foo, @app.routes[8].parent
1108
+ # get "/foo/1/baz/2/bar"
1109
+ assert_equal [:foo, :baz], @app.routes[10].parent
1110
+ end
1111
+
1112
+ it 'should apply parent to controller' do
1113
+ mock_app do
1114
+ controller :project, :parent => :user do
1115
+ get(:index) { "index #{params[:user_id]}"}
1116
+ get(:edit, :with => :id, :parent => :user) { "edit #{params[:id]} #{params[:user_id]}"}
1117
+ get(:show, :with => :id, :parent => :product) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]}"}
1118
+ end
1119
+ end
1120
+
1121
+ user_project_url = "/user/1/project"
1122
+ get user_project_url
1123
+ assert_equal "index 1", body
1124
+ assert_equal user_project_url, @app.url(:project, :index, :user_id => 1)
1125
+
1126
+ user_project_edit_url = "/user/1/project/edit/2"
1127
+ get user_project_edit_url
1128
+ assert_equal "edit 2 1", body
1129
+ assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2)
1130
+
1131
+ user_product_project_url = "/user/1/product/2/project/show/3"
1132
+ get user_product_project_url
1133
+ assert_equal "show 3 1 2", body
1134
+ assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3)
1135
+ end
1136
+
1137
+ it 'should apply parent with shallowing to controller' do
1138
+ mock_app do
1139
+ controller :project do
1140
+ parent :user
1141
+ parent :shop, :optional => true
1142
+ get(:index) { "index #{params[:user_id]} #{params[:shop_id]}" }
1143
+ get(:edit, :with => :id) { "edit #{params[:id]} #{params[:user_id]} #{params[:shop_id]}" }
1144
+ get(:show, :with => :id, :parent => :product) { "show #{params[:id]} #{params[:user_id]} #{params[:product_id]} #{params[:shop_id]}" }
1145
+ end
1146
+ end
1147
+
1148
+ assert_equal "/user/1/project", @app.url(:project, :index, :user_id => 1, :shop_id => nil)
1149
+ assert_equal "/user/1/shop/23/project", @app.url(:project, :index, :user_id => 1, :shop_id => 23)
1150
+
1151
+ user_project_url = "/user/1/project"
1152
+ get user_project_url
1153
+ assert_equal "index 1 ", body
1154
+ assert_equal user_project_url, @app.url(:project, :index, :user_id => 1)
1155
+
1156
+ user_project_edit_url = "/user/1/project/edit/2"
1157
+ get user_project_edit_url
1158
+ assert_equal "edit 2 1 ", body
1159
+ assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2)
1160
+
1161
+ user_product_project_url = "/user/1/product/2/project/show/3"
1162
+ get user_product_project_url
1163
+ assert_equal "show 3 1 2 ", body
1164
+ assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3)
1165
+
1166
+ user_project_url = "/user/1/shop/1/project"
1167
+ get user_project_url
1168
+ assert_equal "index 1 1", body
1169
+ assert_equal user_project_url, @app.url(:project, :index, :user_id => 1, :shop_id => 1)
1170
+
1171
+ user_project_edit_url = "/user/1/shop/1/project/edit/2"
1172
+ get user_project_edit_url
1173
+ assert_equal "edit 2 1 1", body
1174
+ assert_equal user_project_edit_url, @app.url(:project, :edit, :user_id => 1, :id => 2, :shop_id => 1)
1175
+
1176
+ user_product_project_url = "/user/1/shop/1/product/2/project/show/3"
1177
+ get user_product_project_url
1178
+ assert_equal "show 3 1 2 1", body
1179
+ assert_equal user_product_project_url, @app.url(:project, :show, :user_id => 1, :product_id => 2, :id => 3, :shop_id => 1)
1180
+ end
1181
+
1182
+ it 'should respect map in parents with shallowing' do
1183
+ mock_app do
1184
+ controller :project do
1185
+ parent :shop, :map => "/foo/bar"
1186
+ get(:index) { "index #{params[:shop_id]}" }
1187
+ end
1188
+ end
1189
+
1190
+ shop_project_url = "/foo/bar/1/project"
1191
+ get shop_project_url
1192
+ assert_equal "index 1", body
1193
+ assert_equal shop_project_url, @app.url(:project, :index, :shop_id => 1)
1194
+ end
1195
+
1196
+ it 'should use default values' do
1197
+ mock_app do
1198
+ controller :lang => :it do
1199
+ get(:index, :map => "/:lang") { "lang is #{params[:lang]}" }
1200
+ end
1201
+ # This is only for be sure that default values
1202
+ # work only for the given controller
1203
+ get(:foo, :map => "/foo") {}
1204
+ end
1205
+ assert_equal "/it", @app.url(:index)
1206
+ assert_equal "/foo", @app.url(:foo)
1207
+ get "/en"
1208
+ assert_equal "lang is en", body
1209
+ end
1210
+
1211
+ it 'should transitions to the next matching route on pass' do
1212
+ mock_app do
1213
+ get '/:foo' do
1214
+ pass
1215
+ 'Hello Foo'
1216
+ end
1217
+ get '/:bar' do
1218
+ 'Hello World'
1219
+ end
1220
+ end
1221
+
1222
+ get '/za'
1223
+ assert_equal 'Hello World', body
1224
+ end
1225
+
1226
+ it 'should filters by media type' do
1227
+ mock_app do
1228
+ get '/foo', :accepts => [:xml, :json] do
1229
+ request.env['CONTENT_TYPE']
1230
+ end
1231
+ end
1232
+
1233
+ get '/foo', {}, { 'CONTENT_TYPE' => 'application/xml' }
1234
+ assert ok?
1235
+ assert_equal 'application/xml', body
1236
+ assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
1237
+ get '/foo'
1238
+ assert_equal 406, status
1239
+ get '/foo.xml'
1240
+ assert_equal 404, status
1241
+
1242
+ get '/foo', {}, { 'CONTENT_TYPE' => 'application/json' }
1243
+ assert ok?
1244
+ assert_equal 'application/json', body
1245
+ assert_equal 'application/json', response.headers['Content-Type']
1246
+ end
1247
+
1248
+ it 'should filters by media type when using :accepts as controller option' do
1249
+ mock_app do
1250
+ controller accepts: [:xml, :js] do
1251
+ get '/foo' do
1252
+ request.env['CONTENT_TYPE']
1253
+ end
1254
+ end
1255
+ end
1256
+
1257
+ get '/foo', {}, { 'CONTENT_TYPE' => 'application/javascript' }
1258
+ assert ok?
1259
+ assert_equal 'application/javascript', body
1260
+ end
1261
+
1262
+ it 'should filters by accept header' do
1263
+ mock_app do
1264
+ get '/foo', :provides => [:xml, :js] do
1265
+ request.env['HTTP_ACCEPT']
1266
+ end
1267
+ end
1268
+
1269
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1270
+ assert ok?
1271
+ assert_equal 'application/xml', body
1272
+ assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
1273
+
1274
+ get '/foo.xml'
1275
+ assert ok?
1276
+ assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
1277
+
1278
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript' }
1279
+ assert ok?
1280
+ assert_equal 'application/javascript', body
1281
+ assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
1282
+
1283
+ get '/foo.js'
1284
+ assert ok?
1285
+ assert_equal 'application/javascript;charset=utf-8', response.headers['Content-Type']
1286
+
1287
+ get '/foo', {}, { "HTTP_ACCEPT" => 'text/html' }
1288
+ assert_equal 406, status
1289
+ end
1290
+
1291
+ it 'should does not allow global provides' do
1292
+ mock_app do
1293
+ provides :xml
1294
+
1295
+ get("/foo"){ "Foo in #{content_type.inspect}" }
1296
+ get("/bar"){ "Bar in #{content_type.inspect}" }
1297
+ end
1298
+
1299
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1300
+ assert_equal 'Foo in :xml', body
1301
+ get '/foo'
1302
+ assert_equal 'Foo in :xml', body
1303
+
1304
+ get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1305
+ assert_equal 'Bar in nil', body
1306
+ end
1307
+
1308
+ it 'should does not allow global provides in controller' do
1309
+ mock_app do
1310
+ controller :base do
1311
+ provides :xml
1312
+
1313
+ get(:foo, "/foo"){ "Foo in #{content_type.inspect}" }
1314
+ get(:bar, "/bar"){ "Bar in #{content_type.inspect}" }
1315
+ end
1316
+ end
1317
+
1318
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1319
+ assert_equal 'Foo in :xml', body
1320
+ get '/foo'
1321
+ assert_equal 'Foo in :xml', body
1322
+
1323
+ get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
1324
+ assert_equal 'Bar in nil', body
1325
+ end
1326
+
1327
+ it 'should map non named routes in controllers' do
1328
+ mock_app do
1329
+ controller :base do
1330
+ get("/foo") { "ok" }
1331
+ get("/bar") { "ok" }
1332
+ end
1333
+ end
1334
+
1335
+ get "/base/foo"
1336
+ assert ok?
1337
+ get "/base/bar"
1338
+ assert ok?
1339
+ end
1340
+
1341
+ it 'should set content_type to :html for both empty Accept as well as Accept text/html' do
1342
+ mock_app do
1343
+ provides :html
1344
+
1345
+ get("/foo"){ content_type.to_s }
1346
+ end
1347
+
1348
+ get '/foo', {}, {}
1349
+ assert_equal 'html', body
1350
+
1351
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'text/html' }
1352
+ assert_equal 'html', body
1353
+ end
1354
+
1355
+ it 'should set content_type to :html if Accept */*' do
1356
+ mock_app do
1357
+ get("/foo", :provides => [:html, :js]) { content_type.to_s }
1358
+ end
1359
+ get '/foo', {}, {}
1360
+ assert_equal 'html', body
1361
+
1362
+ get '/foo', {}, { 'HTTP_ACCEPT' => '*/*;q=0.5' }
1363
+ assert_equal 'html', body
1364
+ end
1365
+
1366
+ it 'should set content_type to :js if Accept includes both application/javascript and */*;q=0.5' do
1367
+ mock_app do
1368
+ get("/foo", :provides => [:html, :js]) { content_type.to_s }
1369
+ end
1370
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
1371
+ assert_equal 'js', body
1372
+ end
1373
+
1374
+ it 'should set content_type to :html if Accept */* and provides of :any' do
1375
+ mock_app do
1376
+ get("/foo", :provides => :any) { content_type.to_s }
1377
+ end
1378
+
1379
+ get '/foo', {}, { 'HTTP_ACCEPT' => '*/*' }
1380
+ assert_equal 'html', body
1381
+ end
1382
+
1383
+ it 'should set content_type to :js if Accept includes both application/javascript, */*;q=0.5 and provides of :any' do
1384
+ mock_app do
1385
+ get("/foo", :provides => :any) { content_type.to_s }
1386
+ end
1387
+
1388
+ get '/foo', {}, { 'HTTP_ACCEPT' => 'application/javascript, */*;q=0.5' }
1389
+ assert_equal 'js', body
1390
+ end
1391
+
1392
+ it 'should allows custom route-conditions to be set via route options and halt' do
1393
+ protector = Module.new do
1394
+ def protect(*args)
1395
+ condition {
1396
+ unless authorize(params["user"], params["password"])
1397
+ halt 403, "go away"
1398
+ end
1399
+ }
1400
+ end
1401
+ end
1402
+
1403
+ mock_app do
1404
+ register protector
1405
+
1406
+ helpers do
1407
+ def authorize(username, password)
1408
+ username == "foo" && password == "bar"
1409
+ end
1410
+ end
1411
+
1412
+ get "/", :protect => true do
1413
+ "hey"
1414
+ end
1415
+ end
1416
+
1417
+ get "/"
1418
+ assert forbidden?
1419
+ assert_equal "go away", body
1420
+
1421
+ get "/", :user => "foo", :password => "bar"
1422
+ assert ok?
1423
+ assert_equal "hey", body
1424
+ end
1425
+
1426
+ it 'should allows custom route-conditions to be set via route options using two routes' do
1427
+ protector = Module.new do
1428
+ def protect(*args)
1429
+ condition { authorize(params["user"], params["password"]) }
1430
+ end
1431
+ end
1432
+
1433
+ mock_app do
1434
+ register protector
1435
+
1436
+ helpers do
1437
+ def authorize(username, password)
1438
+ username == "foo" && password == "bar"
1439
+ end
1440
+ end
1441
+
1442
+ get "/", :protect => true do
1443
+ "hey"
1444
+ end
1445
+
1446
+ get "/" do
1447
+ "go away"
1448
+ end
1449
+ end
1450
+
1451
+ get "/"
1452
+ assert_equal "go away", body
1453
+
1454
+ get "/", :user => "foo", :password => "bar"
1455
+ assert ok?
1456
+ assert_equal "hey", body
1457
+ end
1458
+
1459
+ it 'should allow concise routing' do
1460
+ mock_app do
1461
+ get :index, ":id" do
1462
+ params[:id]
1463
+ end
1464
+
1465
+ get :map, "route/:id" do
1466
+ params[:id]
1467
+ end
1468
+ end
1469
+
1470
+ get "/123"
1471
+ assert_equal "123", body
1472
+
1473
+ get "/route/123"
1474
+ assert_equal "123", body
1475
+ end
1476
+
1477
+ it 'should support halting with 404 and message' do
1478
+ mock_app do
1479
+ controller do
1480
+ get :index do
1481
+ halt 404, "not found"
1482
+ end
1483
+ end
1484
+ end
1485
+
1486
+ get "/"
1487
+ assert_equal 404, status
1488
+ assert_equal "not found", body
1489
+ end
1490
+
1491
+ it 'should allow passing & halting in before filters' do
1492
+ mock_app do
1493
+ controller do
1494
+ before { env['QUERY_STRING'] == 'secret' or pass }
1495
+ get :index do
1496
+ "secret index"
1497
+ end
1498
+ end
1499
+
1500
+ controller do
1501
+ before { env['QUERY_STRING'] == 'halt' and halt 401, 'go away!' }
1502
+ get :index do
1503
+ "index"
1504
+ end
1505
+ end
1506
+ end
1507
+
1508
+ get "/?secret"
1509
+ assert_equal "secret index", body
1510
+
1511
+ get "/?halt"
1512
+ assert_equal "go away!", body
1513
+ assert_equal 401, status
1514
+
1515
+ get "/"
1516
+ assert_equal "index", body
1517
+ end
1518
+
1519
+ it 'should scope filters in the given controller' do
1520
+ mock_app do
1521
+ before { @global = 'global' }
1522
+ after { @global = nil }
1523
+
1524
+ controller :foo do
1525
+ before { @foo = :foo }
1526
+ after { @foo = nil }
1527
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
1528
+ end
1529
+
1530
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
1531
+
1532
+ controller :bar do
1533
+ before { @bar = :bar }
1534
+ after { @bar = nil }
1535
+ get("/") { [@foo, @bar, @global].compact.join(" ") }
1536
+ end
1537
+ end
1538
+
1539
+ get "/bar"
1540
+ assert_equal "bar global", body
1541
+
1542
+ get "/foo"
1543
+ assert_equal "foo global", body
1544
+
1545
+ get "/"
1546
+ assert_equal "global", body
1547
+ end
1548
+
1549
+ it 'should works with optionals params' do
1550
+ mock_app do
1551
+ get("/foo(/:bar)?") { params[:bar] }
1552
+ end
1553
+
1554
+ get "/foo/bar"
1555
+ assert_equal "bar", body
1556
+
1557
+ get "/foo"
1558
+ assert_equal "", body
1559
+ end
1560
+
1561
+ it 'should work with multiple dashed params' do
1562
+ mock_app do
1563
+ get "/route/:foo/:bar/:baz", :provides => :html do
1564
+ "#{params[:foo]};#{params[:bar]};#{params[:baz]}"
1565
+ end
1566
+ end
1567
+
1568
+ get "/route/foo/bar/baz"
1569
+ assert_equal 'foo;bar;baz', body
1570
+
1571
+ get "/route/foo/bar-whatever/baz"
1572
+ assert_equal 'foo;bar-whatever;baz', body
1573
+ end
1574
+
1575
+ it 'should work with arbitrary params' do
1576
+ mock_app do
1577
+ get(:testing) { params[:foo] }
1578
+ end
1579
+
1580
+ url = @app.url(:testing, :foo => 'bar')
1581
+ assert_equal "/testing?foo=bar", url
1582
+ get url
1583
+ assert_equal "bar", body
1584
+ end
1585
+
1586
+ it 'should ignore nil params' do
1587
+ mock_app do
1588
+ get(:testing, :provides => [:html, :json]) do
1589
+ end
1590
+ end
1591
+ assert_equal '/testing.html', @app.url(:testing, :format => :html)
1592
+ assert_equal '/testing', @app.url(:testing, :format => nil)
1593
+ end
1594
+
1595
+ it 'should be able to access params in a before filter' do
1596
+ username_from_before_filter = nil
1597
+
1598
+ mock_app do
1599
+ before do
1600
+ username_from_before_filter = params[:username]
1601
+ end
1602
+
1603
+ get :users, :with => :username do
1604
+ end
1605
+ end
1606
+ get '/users/josh'
1607
+ assert_equal 'josh', username_from_before_filter
1608
+ end
1609
+
1610
+ it 'should be able to access params normally when a before filter is specified' do
1611
+ mock_app do
1612
+ before { }
1613
+ get :index do
1614
+ params.inspect
1615
+ end
1616
+ end
1617
+ get '/?test=what'
1618
+ assert_equal '{"test"=>"what"}', body
1619
+ end
1620
+
1621
+ it 'should work only for the given controller and route when using before-filter with route name' do
1622
+ mock_app do
1623
+ controller :foo do
1624
+ before(:index) { @a = "only to :index" }
1625
+ get(:index) { @a }
1626
+ get(:main) { @a }
1627
+ end
1628
+ end
1629
+ get '/foo/'
1630
+ assert_equal 'only to :index', body
1631
+ get '/foo/main'
1632
+ assert_equal '', body
1633
+ end
1634
+
1635
+ it 'should work only for the given controller and route when using after-filter with route name' do
1636
+ mock_app do
1637
+ controller :after_controller do
1638
+ global = "global variable"
1639
+ get(:index) { global }
1640
+ get(:main) { global }
1641
+ after(:index) { global = nil }
1642
+ end
1643
+ end
1644
+ get '/after_controller'
1645
+ assert_equal 'global variable', body
1646
+ get '/after_controller'
1647
+ assert_equal '', body
1648
+ end
1649
+
1650
+ it 'should execute the before/after filters when they are inserted after the target route' do
1651
+ mock_app do
1652
+ controller :after_test do
1653
+ global = "global variable"
1654
+ get(:index) { global }
1655
+ get(:foo) { global }
1656
+ before(:index) { global.delete!(" ") }
1657
+ after(:index) { global = "after" }
1658
+ end
1659
+ end
1660
+ get '/after_test'
1661
+ assert_equal 'globalvariable', body
1662
+ get '/after_test/foo'
1663
+ assert_equal 'after', body
1664
+ end
1665
+
1666
+ it 'should work with controller and arbitrary params' do
1667
+ mock_app do
1668
+ get(:testing) { params[:foo] }
1669
+ controller :test1 do
1670
+ get(:url1) { params[:foo] }
1671
+ get(:url2, :provides => [:html, :json]) { params[:foo] }
1672
+ end
1673
+ end
1674
+
1675
+ url = @app.url(:test1, :url1, :foo => 'bar1')
1676
+ assert_equal "/test1/url1?foo=bar1", url
1677
+ get url
1678
+ assert_equal "bar1", body
1679
+
1680
+ url = @app.url(:test1, :url2, :foo => 'bar2')
1681
+ assert_equal "/test1/url2?foo=bar2", url
1682
+ get url
1683
+ assert_equal "bar2", body
1684
+ end
1685
+
1686
+ it 'should parse two routes with the same path but different http verbs' do
1687
+ mock_app do
1688
+ get(:index) { "This is the get index" }
1689
+ post(:index) { "This is the post index" }
1690
+ end
1691
+ get "/"
1692
+ assert_equal "This is the get index", body
1693
+ post "/"
1694
+ assert_equal "This is the post index", body
1695
+ end
1696
+
1697
+ it 'should use optionals params' do
1698
+ mock_app do
1699
+ get(:index, :map => "/:foo(/:bar)?") { "#{params[:foo]}-#{params[:bar]}" }
1700
+ end
1701
+ get "/foo"
1702
+ assert_equal "foo-", body
1703
+ get "/foo/bar"
1704
+ assert_equal "foo-bar", body
1705
+ end
1706
+
1707
+ it 'should parse two routes with the same path but different http verbs and provides' do
1708
+ mock_app do
1709
+ get(:index, :provides => [:html, :json]) { "This is the get index.#{content_type}" }
1710
+ post(:index, :provides => [:html, :json]) { "This is the post index.#{content_type}" }
1711
+ end
1712
+ get "/"
1713
+ assert_equal "This is the get index.html", body
1714
+ post "/"
1715
+ assert_equal "This is the post index.html", body
1716
+ get "/.json"
1717
+ assert_equal "This is the get index.json", body
1718
+ get "/.js"
1719
+ assert_equal 404, status
1720
+ post "/.json"
1721
+ assert_equal "This is the post index.json", body
1722
+ post "/.js"
1723
+ assert_equal 404, status
1724
+ end
1725
+
1726
+ it 'should allow controller level mapping' do
1727
+ mock_app do
1728
+ controller :map => "controller-:id" do
1729
+ get(:url3) { "#{params[:id]}" }
1730
+ get(:url4, :map => 'test-:id2') { "#{params[:id]}, #{params[:id2]}" }
1731
+ end
1732
+ end
1733
+
1734
+ url = @app.url(:url3, :id => 1)
1735
+ assert_equal "/controller-1/url3", url
1736
+ get url
1737
+ assert_equal "1", body
1738
+
1739
+ url = @app.url(:url4, 1, 2)
1740
+ assert_equal "/controller-1/test-2", url
1741
+ get url
1742
+ assert_equal "1, 2", body
1743
+ end
1744
+
1745
+ it 'should replace name of named controller with mapping path' do
1746
+ mock_app do
1747
+ controller :ugly, :map => "/pretty/:id" do
1748
+ get(:url3) { "#{params[:id]}" }
1749
+ get(:url4, :map => 'test-:id2') { "#{params[:id]}, #{params[:id2]}" }
1750
+ end
1751
+ controller :voldemort, :map => "" do
1752
+ get(:url5) { "okay" }
1753
+ end
1754
+ end
1755
+
1756
+ url = @app.url(:ugly, :url3, :id => 1)
1757
+ assert_equal "/pretty/1/url3", url
1758
+ get url
1759
+ assert_equal "1", body
1760
+
1761
+ url = @app.url(:ugly, :url4, 3, 5)
1762
+ assert_equal "/pretty/3/test-5", url
1763
+ get url
1764
+ assert_equal "3, 5", body
1765
+
1766
+ url = @app.url(:voldemort, :url5)
1767
+ assert_equal "/url5", url
1768
+ get url
1769
+ assert_equal 'okay', body
1770
+ end
1771
+
1772
+ it 'should use absolute and relative maps' do
1773
+ mock_app do
1774
+ controller :one do
1775
+ parent :three
1776
+ get :index, :map => 'one' do; end
1777
+ get :index2, :map => '/one' do; end
1778
+ end
1779
+
1780
+ controller :two, :map => 'two' do
1781
+ parent :three
1782
+ get :index, :map => 'two' do; end
1783
+ get :index2, :map => '/two', :with => :id do; end
1784
+ end
1785
+ end
1786
+ assert_equal "/three/three_id/one", @app.url(:one, :index, 'three_id')
1787
+ assert_equal "/one", @app.url(:one, :index2)
1788
+ assert_equal "/two/three/three_id/two", @app.url(:two, :index, 'three_id')
1789
+ assert_equal "/two/four_id", @app.url(:two, :index2, 'four_id')
1790
+ end
1791
+
1792
+ it 'should work with params and parent options' do
1793
+ mock_app do
1794
+ controller :test2, :parent => :parent1, :parent1_id => 1 do
1795
+ get(:url3) { params[:foo] }
1796
+ get(:url4, :with => :with1) { params[:foo] }
1797
+ get(:url5, :with => :with2, :provides => [:html]) { params[:foo] }
1798
+ end
1799
+ end
1800
+
1801
+ url = @app.url(:test2, :url3, :foo => 'bar3')
1802
+ assert_equal "/parent1/1/test2/url3?foo=bar3", url
1803
+ get url
1804
+ assert_equal "bar3", body
1805
+
1806
+ url = @app.url(:test2, :url4, :with1 => 'awith1', :foo => 'bar4')
1807
+ assert_equal "/parent1/1/test2/url4/awith1?foo=bar4", url
1808
+ get url
1809
+ assert_equal "bar4", body
1810
+
1811
+ url = @app.url(:test2, :url5, :with2 => 'awith1', :foo => 'bar5')
1812
+ assert_equal "/parent1/1/test2/url5/awith1?foo=bar5", url
1813
+ get url
1814
+ assert_equal "bar5", body
1815
+ end
1816
+
1817
+ it 'should parse params without explicit provides for every matching route' do
1818
+ mock_app do
1819
+ get(:index, :map => "/foos/:bar") { "get bar = #{params[:bar]}" }
1820
+ post :create, :map => "/foos/:bar", :provides => [:html, :js] do
1821
+ "post bar = #{params[:bar]}"
1822
+ end
1823
+ end
1824
+
1825
+ get "/foos/hello"
1826
+ assert_equal "get bar = hello", body
1827
+ post "/foos/hello"
1828
+ assert_equal "post bar = hello", body
1829
+ post "/foos/hello.js"
1830
+ assert_equal "post bar = hello", body
1831
+ end
1832
+
1833
+ it 'should properly route to first foo with two similar routes' do
1834
+ mock_app do
1835
+ controllers do
1836
+ get('/foo/') { "this is foo" }
1837
+ get(:show, :map => "/foo/:bar/:id") { "/foo/#{params[:bar]}/#{params[:id]}" }
1838
+ end
1839
+ end
1840
+ get "/foo"
1841
+ assert_equal "this is foo", body
1842
+ get "/foo/"
1843
+ assert_equal "this is foo", body
1844
+ get '/foo/5/10'
1845
+ assert_equal "/foo/5/10", body
1846
+ end
1847
+
1848
+ it 'should index routes should be optional when nested' do
1849
+ mock_app do
1850
+ controller '/users', :provides => [:json] do
1851
+ get '/' do
1852
+ "foo"
1853
+ end
1854
+ end
1855
+ end
1856
+ get "/users.json"
1857
+ assert_equal "foo", body
1858
+ end
1859
+
1860
+ it 'should use provides as conditional' do
1861
+ mock_app do
1862
+ provides :json
1863
+ get "/" do
1864
+ "foo"
1865
+ end
1866
+ end
1867
+ get "/.json"
1868
+ assert_equal "foo", body
1869
+ end
1870
+
1871
+ it 'should reset provides for routes that did not use it' do
1872
+ mock_app do
1873
+ get('/foo', :provides => :js){}
1874
+ get('/bar'){}
1875
+ end
1876
+ get '/foo'
1877
+ assert ok?
1878
+ get '/foo.js'
1879
+ assert ok?
1880
+ get '/bar'
1881
+ assert ok?
1882
+ get '/bar.js'
1883
+ assert_equal 404, status
1884
+ end
1885
+
1886
+ it 'should pass controller conditions to each route' do
1887
+ counter = 0
1888
+
1889
+ mock_app do
1890
+ self.class.send(:define_method, :increment!) do |*args|
1891
+ condition { counter += 1 }
1892
+ end
1893
+
1894
+ controller :posts, :conditions => {:increment! => true} do
1895
+ get("/foo") { "foo" }
1896
+ get("/bar") { "bar" }
1897
+ end
1898
+
1899
+ end
1900
+
1901
+ get "/posts/foo"
1902
+ get "/posts/bar"
1903
+ assert_equal 2, counter
1904
+ end
1905
+
1906
+ it 'should allow controller conditions to be overridden' do
1907
+ counter = 0
1908
+
1909
+ mock_app do
1910
+ self.class.send(:define_method, :increment!) do |increment|
1911
+ condition { counter += 1 } if increment
1912
+ end
1913
+
1914
+ controller :posts, :conditions => {:increment! => true} do
1915
+ get("/foo") { "foo" }
1916
+ get("/bar", :increment! => false) { "bar" }
1917
+ end
1918
+
1919
+ end
1920
+
1921
+ get "/posts/foo"
1922
+ get "/posts/bar"
1923
+ assert_equal 1, counter
1924
+ end
1925
+
1926
+ it 'should parse params with class level provides' do
1927
+ mock_app do
1928
+ controllers :posts, :provides => [:html, :js] do
1929
+ post(:create, :map => "/foo/:bar/:baz/:id") {
1930
+ "POST CREATE #{params[:bar]} - #{params[:baz]} - #{params[:id]}"
1931
+ }
1932
+ end
1933
+ controllers :topics, :provides => [:js, :html] do
1934
+ get(:show, :map => "/foo/:bar/:baz/:id") { render "topics/show" }
1935
+ post(:create, :map => "/foo/:bar/:baz") { "TOPICS CREATE #{params[:bar]} - #{params[:baz]}" }
1936
+ end
1937
+ end
1938
+ post "/foo/bar/baz.js"
1939
+ assert_equal "TOPICS CREATE bar - baz", body, "should parse params with explicit .js"
1940
+ post @app.url(:topics, :create, :format => :js, :bar => 'bar', :baz => 'baz')
1941
+ assert_equal "TOPICS CREATE bar - baz", body, "should parse params from generated url"
1942
+ post "/foo/bar/baz/5.js"
1943
+ assert_equal "POST CREATE bar - baz - 5", body
1944
+ post @app.url(:posts, :create, :format => :js, :bar => 'bar', :baz => 'baz', :id => 5)
1945
+ assert_equal "POST CREATE bar - baz - 5", body
1946
+ end
1947
+
1948
+ it 'should parse params properly with inline provides' do
1949
+ mock_app do
1950
+ controllers :posts do
1951
+ post(:create, :map => "/foo/:bar/:baz/:id", :provides => [:html, :js]) {
1952
+ "POST CREATE #{params[:bar]} - #{params[:baz]} - #{params[:id]}"
1953
+ }
1954
+ end
1955
+ controllers :topics do
1956
+ get(:show, :map => "/foo/:bar/:baz/:id", :provides => [:html, :js]) { render "topics/show" }
1957
+ post(:create, :map => "/foo/:bar/:baz", :provides => [:html, :js]) { "TOPICS CREATE #{params[:bar]} - #{params[:baz]}" }
1958
+ end
1959
+ end
1960
+ post @app.url(:topics, :create, :format => :js, :bar => 'bar', :baz => 'baz')
1961
+ assert_equal "TOPICS CREATE bar - baz", body, "should properly post to topics create action"
1962
+ post @app.url(:posts, :create, :format => :js, :bar => 'bar', :baz => 'baz', :id => 5)
1963
+ assert_equal "POST CREATE bar - baz - 5", body, "should properly post to create action"
1964
+ end
1965
+
1966
+ it 'should have overideable format' do
1967
+ ::Rack::Mime::MIME_TYPES[".other"] = "text/html"
1968
+ mock_app do
1969
+ before do
1970
+ params[:format] ||= :other
1971
+ end
1972
+ get("/format_test", :provides => [:html, :other]){ content_type.to_s }
1973
+ end
1974
+ get "/format_test"
1975
+ assert_equal "other", body
1976
+ ::Rack::Mime::MIME_TYPES.delete('.other')
1977
+ end
1978
+
1979
+ it 'should invokes handlers registered with ::error when raised' do
1980
+ mock_app do
1981
+ set :raise_errors, false
1982
+ error(FooError) { 'Foo!' }
1983
+ get '/' do
1984
+ raise FooError
1985
+ end
1986
+ end
1987
+ get '/'
1988
+ assert_equal 500, status
1989
+ assert_equal 'Foo!', body
1990
+ end
1991
+
1992
+ it 'should have MethodOverride middleware' do
1993
+ mock_app do
1994
+ put('/') { 'okay' }
1995
+ end
1996
+ assert @app.method_override?
1997
+ post '/', {'_method'=>'PUT'}, {}
1998
+ assert_equal 200, status
1999
+ assert_equal 'okay', body
2000
+ end
2001
+
2002
+ it 'should return value from params' do
2003
+ mock_app do
2004
+ get("/foo/:bar"){ raise "'bar' should be a string" unless params[:bar].kind_of? String}
2005
+ end
2006
+ get "/foo/50"
2007
+ assert ok?
2008
+ end
2009
+
2010
+ it 'should return params as a HashWithIndifferentAccess object via GET' do
2011
+ mock_app do
2012
+ get('/foo/:bar') { "#{params["bar"]} #{params[:bar]}" }
2013
+ get(:foo, :map => '/prefix/:var') { "#{params["var"]} #{params[:var]}" }
2014
+ end
2015
+
2016
+ get('/foo/some_text')
2017
+ assert_equal "some_text some_text", body
2018
+
2019
+ get('/prefix/var')
2020
+ assert_equal "var var", body
2021
+ end
2022
+
2023
+ it 'should return params as a HashWithIndifferentAccess object via POST' do
2024
+ mock_app do
2025
+ post('/user') do
2026
+ "#{params["user"]["full_name"]} #{params[:user][:full_name]}"
2027
+ end
2028
+ end
2029
+
2030
+ post '/user', {:user => {:full_name => 'example user'}}
2031
+ assert_equal "example user example user", body
2032
+
2033
+ post '/user', {"user" => {"full_name" => 'example user'}}
2034
+ assert_equal "example user example user", body
2035
+ end
2036
+
2037
+ it 'should have MethodOverride middleware with more options' do
2038
+ mock_app do
2039
+ put('/hi', :provides => [:json]) { 'hi' }
2040
+ end
2041
+ post '/hi', {'_method'=>'PUT'}
2042
+ assert_equal 200, status
2043
+ assert_equal 'hi', body
2044
+ post '/hi.json', {'_method'=>'PUT'}
2045
+ assert_equal 200, status
2046
+ assert_equal 'hi', body
2047
+ post '/hi.json'
2048
+ assert_equal 405, status
2049
+ end
2050
+
2051
+ it 'should parse nested params' do
2052
+ mock_app do
2053
+ get(:index) { "%s %s" % [params[:account][:name], params[:account][:surname]] }
2054
+ end
2055
+ get "/?" + { :account => { :name => 'foo', :surname => 'bar' } }.to_query
2056
+ assert_equal 'foo bar', body
2057
+ get @app.url(:index, "account[name]" => "foo", "account[surname]" => "bar")
2058
+ assert_equal 'foo bar', body
2059
+ end
2060
+
2061
+ it 'should render sinatra NotFound page' do
2062
+ mock_app { set :environment, :development }
2063
+ get "/"
2064
+ assert_equal 404, status
2065
+ assert_match %r{(Sinatra doesn&rsquo;t know this ditty.|<h1>Not Found</h1>)}, body
2066
+ end
2067
+
2068
+ it 'should render a custom NotFound page' do
2069
+ mock_app do
2070
+ error(Sinatra::NotFound) { "not found" }
2071
+ end
2072
+ get "/"
2073
+ assert_equal 404, status
2074
+ assert_match /not found/, body
2075
+ end
2076
+
2077
+ it 'should render a custom 404 page using not_found' do
2078
+ mock_app do
2079
+ not_found { "custom 404 not found" }
2080
+ end
2081
+ get "/"
2082
+ assert_equal 404, status
2083
+ assert_equal "custom 404 not found", body
2084
+ end
2085
+
2086
+ it 'should render a custom error page using error method' do
2087
+ mock_app do
2088
+ error(404) { "custom 404 error" }
2089
+ end
2090
+ get "/"
2091
+ assert_equal 404, status
2092
+ assert_equal "custom 404 error", body
2093
+ end
2094
+
2095
+ it 'should render a custom 403 page' do
2096
+ mock_app do
2097
+ error(403) { "custom 403 not found" }
2098
+ get("/") { status 403 }
2099
+ end
2100
+ get "/"
2101
+ assert_equal 403, status
2102
+ assert_equal "custom 403 not found", body
2103
+ end
2104
+
2105
+ it 'should recognize paths' do
2106
+ mock_app do
2107
+ controller :foo do
2108
+ get(:bar, :map => "/my/:id/custom-route") { }
2109
+ end
2110
+ get(:simple, :map => "/simple/:id") { }
2111
+ get(:with_format, :with => :id, :provides => :js) { }
2112
+ end
2113
+ assert_equal [:"foo bar", { :id => "fantastic" }.with_indifferent_access], @app.recognize_path(@app.url(:foo, :bar, :id => :fantastic))
2114
+ assert_equal [:"foo bar", { :id => "18" }.with_indifferent_access], @app.recognize_path(@app.url(:foo, :bar, :id => 18))
2115
+ assert_equal [:simple, { :id => "bar" }.with_indifferent_access], @app.recognize_path(@app.url(:simple, :id => "bar"))
2116
+ assert_equal [:simple, { :id => "true" }.with_indifferent_access], @app.recognize_path(@app.url(:simple, :id => true))
2117
+ assert_equal [:simple, { :id => "9" }.with_indifferent_access], @app.recognize_path(@app.url(:simple, :id => 9))
2118
+ assert_equal [:with_format, { :id => "bar", :format => "js" }.with_indifferent_access], @app.recognize_path(@app.url(:with_format, :id => "bar", :format => :js))
2119
+ assert_equal [:with_format, { :id => "true", :format => "js" }.with_indifferent_access], @app.recognize_path(@app.url(:with_format, :id => true, :format => "js"))
2120
+ assert_equal [:with_format, { :id => "9", :format => "js" }.with_indifferent_access], @app.recognize_path(@app.url(:with_format, :id => 9, :format => :js))
2121
+ end
2122
+
2123
+ it 'should have current_path' do
2124
+ mock_app do
2125
+ controller :foo do
2126
+ get(:index) { current_path }
2127
+ get :bar, :map => "/paginate/:page" do
2128
+ current_path
2129
+ end
2130
+ get(:after) { current_path }
2131
+ end
2132
+ end
2133
+ get "/paginate/10"
2134
+ assert_equal "/paginate/10", body
2135
+ get "/foo/after"
2136
+ assert_equal "/foo/after", body
2137
+ get "/foo"
2138
+ assert_equal "/foo", body
2139
+ end
2140
+
2141
+ it 'should accept :map and :parent' do
2142
+ mock_app do
2143
+ controller :posts do
2144
+ get :show, :parent => :users, :map => "posts/:id" do
2145
+ "#{params[:user_id]}-#{params[:id]}"
2146
+ end
2147
+ end
2148
+ end
2149
+ get '/users/123/posts/321'
2150
+ assert_equal "123-321", body
2151
+ end
2152
+
2153
+ it 'should change params in current_path' do
2154
+ mock_app do
2155
+ get :index, :map => "/paginate/:page" do
2156
+ current_path(:page => 66)
2157
+ end
2158
+ end
2159
+ get @app.url(:index, :page => 10)
2160
+ assert_equal "/paginate/66", body
2161
+ end
2162
+
2163
+ it 'should not route get :users, :with => :id to /users//' do
2164
+ mock_app do
2165
+ get(:users, :with => :id) { 'boo' }
2166
+ end
2167
+ get '/users//'
2168
+ assert_equal 404, status
2169
+ end
2170
+
2171
+ it "should support splat params" do
2172
+ mock_app do
2173
+ get "/say/*/to/*" do
2174
+ params[:splat].inspect
2175
+ end
2176
+ end
2177
+ get "/say/hello/to/world"
2178
+ assert_equal %Q[["hello", "world"]], body
2179
+ end
2180
+
2181
+ it "should recognize the route containing splat params if path is ended with slash" do
2182
+ mock_app do
2183
+ get "/splat/*" do
2184
+ "slash!"
2185
+ end
2186
+ end
2187
+ get "/splat"
2188
+ assert_equal 404, status
2189
+ get "/splat/"
2190
+ assert_equal "slash!", body
2191
+ end
2192
+
2193
+ it "should match correctly paths even if the free regex route exists" do
2194
+ mock_app do
2195
+ get %r{/b/(?<aa>\w+)/(?<bb>\w+)} do
2196
+ "free regex"
2197
+ end
2198
+
2199
+ put '/b/:b/:c', :csrf_protection => false do
2200
+ params.inspect
2201
+ end
2202
+ end
2203
+ put "/b/x/y"
2204
+ assert_equal '{"b"=>"x", "c"=>"y"}', body
2205
+ end
2206
+
2207
+ it "should support named captures like %r{/hello/(?<person>[^/?#]+)} on Ruby >= 1.9" do
2208
+ next if RUBY_VERSION < '1.9'
2209
+ mock_app do
2210
+ get Regexp.new('/hello/(?<person>[^/?#]+)') do
2211
+ "Hello #{params['person']}"
2212
+ end
2213
+ end
2214
+ get '/hello/Frank'
2215
+ assert_equal 'Hello Frank', body
2216
+ end
2217
+
2218
+ it 'supports regular expression look-alike routes' do
2219
+ mock_app do
2220
+ get(RegexpLookAlike.new) do
2221
+ [params[:one], params[:two], params[:three], params[:four]].join(" ")
2222
+ end
2223
+ end
2224
+
2225
+ get '/this/is/a/test/'
2226
+ assert ok?
2227
+ assert_equal 'this is a test', body
2228
+ end
2229
+
2230
+ it "uses optional block passed to pass as route block if no other route is found" do
2231
+ mock_app do
2232
+ get "/" do
2233
+ pass do
2234
+ "this"
2235
+ end
2236
+ "not this"
2237
+ end
2238
+ end
2239
+
2240
+ get "/"
2241
+ assert ok?
2242
+ assert_equal "this", body
2243
+ end
2244
+
2245
+ it "supports mixing multiple splat params like /*/foo/*/* as block parameters" do
2246
+ mock_app do
2247
+ get '/*/foo/*/*' do |foo, bar, baz|
2248
+ "#{foo}, #{bar}, #{baz}"
2249
+ end
2250
+ end
2251
+
2252
+ get '/bar/foo/bling/baz/boom'
2253
+ assert ok?
2254
+ assert_equal 'bar, bling, baz/boom', body
2255
+ end
2256
+
2257
+ it "should be able to use PathRouter#recognize to recognize routes" do
2258
+ mock_app do
2259
+ get(:sample){}
2260
+ end
2261
+ env = Rack::MockRequest.env_for("/sample")
2262
+ request = Rack::Request.new(env)
2263
+ assert_equal :sample, @app.router.recognize(request).first.name
2264
+ end
2265
+
2266
+ it "should be able to use PathRouter#recognize to recognize routes by using Rack::MockRequest" do
2267
+ mock_app do
2268
+ get(:mock_sample){}
2269
+ end
2270
+ env = Rack::MockRequest.env_for("/mock_sample")
2271
+ assert_equal :mock_sample, @app.router.recognize(env).first.name
2272
+ env = Rack::MockRequest.env_for("/invalid")
2273
+ assert_equal [], @app.router.recognize(env)
2274
+ end
2275
+
2276
+ it "should be able to use params after sending request" do
2277
+ last_app = mock_app do
2278
+ get("/foo/:id"){ params.inspect }
2279
+ end
2280
+ get "/foo/123"
2281
+ assert_equal({"id"=>"123"}, Thread.current['tennpipes.instance'].instance_variable_get(:@params))
2282
+ end
2283
+
2284
+ it "should raise an exception if block arity is not same with captured params size" do
2285
+ assert_raises(Tennpipes::Routing::BlockArityError) do
2286
+ mock_app do
2287
+ get("/sample/:a/:b") { |a| }
2288
+ end
2289
+ end
2290
+ end
2291
+
2292
+ it "should pass format value as a block parameter" do
2293
+ mock_app do
2294
+ get "/sample/:a/:b", :provides => :xml do |a, b, format|
2295
+ "#{a}, #{b}, #{format}"
2296
+ end
2297
+ end
2298
+ get "/sample/foo/bar"
2299
+ assert_equal "foo, bar, ", body
2300
+ get "/sample/foo/bar.xml"
2301
+ assert_equal "foo, bar, xml", body
2302
+ end
2303
+
2304
+ it "should allow negative arity in route block" do
2305
+ mock_app do
2306
+ get("/:a/sample/*/*") { |*all| }
2307
+ end
2308
+ end
2309
+
2310
+ it "should be able to use splat and named captues" do
2311
+ mock_app do
2312
+ get("/:a/:b/*/*/*") { |a, b, *splats| "#{a}, #{b}, (#{splats * ","})" }
2313
+ end
2314
+ get "/123/456/a/b/c"
2315
+ assert_equal "123, 456, (a,b,c)", body
2316
+ end
2317
+
2318
+ it "can modify the request" do
2319
+ mock_app do
2320
+ get('/foo') { request.path_info = '/bar'; pass }
2321
+ get('/bar') { 'bar' }
2322
+ end
2323
+
2324
+ get '/foo'
2325
+ assert ok?
2326
+ assert_equal 'bar', body
2327
+ end
2328
+ end