tennpipes-base 3.6.6

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