Upgraded Rails and RSpec
[monkeycharger.git] / vendor / rails / actionpack / test / controller / routing_test.rb
blob5198efd8e6077771b13c3268a6c4ad55e957a4d0
1 require "#{File.dirname(__FILE__)}/../abstract_unit"
2 require "#{File.dirname(__FILE__)}/fake_controllers"
3 require 'action_controller/routing'
5 RunTimeTests = ARGV.include? 'time'
6 ROUTING = ActionController::Routing
8 class ROUTING::RouteBuilder
9   attr_reader :warn_output
11   def warn(msg)
12     (@warn_output ||= []) << msg
13   end
14 end
16 # See RFC 3986, section 3.3 for allowed path characters.
17 class UriReservedCharactersRoutingTest < Test::Unit::TestCase
18   def setup
19     ActionController::Routing.use_controllers! ['controller']
20     @set = ActionController::Routing::RouteSet.new
21     @set.draw do |map|
22       map.connect ':controller/:action/:variable'
23     end
25     safe, unsafe = %w(: @ & = + $ , ;), %w(^ / ? # [ ])
26     hex = unsafe.map { |char| '%' + char.unpack('H2').first.upcase }
28     @segment = "#{safe}#{unsafe}".freeze
29     @escaped = "#{safe}#{hex}".freeze
30   end
32   def test_route_generation_escapes_unsafe_path_characters
33     assert_equal "/contr#{@segment}oller/act#{@escaped}ion/var#{@escaped}iable",
34       @set.generate(:controller => "contr#{@segment}oller",
35                     :action => "act#{@segment}ion",
36                     :variable => "var#{@segment}iable")
37   end
39   def test_route_recognition_unescapes_path_components
40     options = { :controller => "controller",
41                 :action => "act#{@segment}ion",
42                 :variable => "var#{@segment}iable" }
43     assert_equal options, @set.recognize_path("/controller/act#{@escaped}ion/var#{@escaped}iable")
44   end
45 end
47 class LegacyRouteSetTests < Test::Unit::TestCase
48   attr_reader :rs
49   def setup
50     # These tests assume optimisation is on, so re-enable it.
51     ActionController::Base.optimise_named_routes = true
53     @rs = ::ActionController::Routing::RouteSet.new
54     @rs.draw {|m| m.connect ':controller/:action/:id' }
56     ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed)
57   end
59   def test_default_setup
60     assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
61     assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list"))
62     assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10"))
63     
64     assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10"))
65     
66     assert_equal '/admin/user/show/10', rs.generate(:controller => 'admin/user', :action => 'show', :id => 10)
67     
68     assert_equal '/admin/user/show', rs.generate({:action => 'show'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
69     assert_equal '/admin/user/list/10', rs.generate({}, {:controller => 'admin/user', :action => 'list', :id => '10'})
71     assert_equal '/admin/stuff', rs.generate({:controller => 'stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
72     assert_equal '/stuff', rs.generate({:controller => '/stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
73   end
74   
75   def test_ignores_leading_slash
76     @rs.draw {|m| m.connect '/:controller/:action/:id'}
77     test_default_setup
78   end
79   
80   def test_time_recognition
81     n = 10000
82     if RunTimeTests
83       GC.start
84       rectime = Benchmark.realtime do
85         n.times do
86           rs.recognize_path("content")
87           rs.recognize_path("content/list")
88           rs.recognize_path("content/show/10")
89           rs.recognize_path("admin/user")
90           rs.recognize_path("admin/user/list")
91           rs.recognize_path("admin/user/show/10")
92         end
93       end
94       puts "\n\nRecognition (RouteSet):"
95       per_url = rectime / (n * 6)
96       puts "#{per_url * 1000} ms/url"
97       puts "#{1 / per_url} url/s\n\n"
98     end
99   end
100   def test_time_generation
101     n = 5000
102     if RunTimeTests
103       GC.start
104       pairs = [
105         [{:controller => 'content', :action => 'index'}, {:controller => 'content', :action => 'show'}],
106         [{:controller => 'content'}, {:controller => 'content', :action => 'index'}],   
107         [{:controller => 'content', :action => 'list'}, {:controller => 'content', :action => 'index'}],
108         [{:controller => 'content', :action => 'show', :id => '10'}, {:controller => 'content', :action => 'list'}],
109         [{:controller => 'admin/user', :action => 'index'}, {:controller => 'admin/user', :action => 'show'}],
110         [{:controller => 'admin/user'}, {:controller => 'admin/user', :action => 'index'}],
111         [{:controller => 'admin/user', :action => 'list'}, {:controller => 'admin/user', :action => 'index'}],
112         [{:controller => 'admin/user', :action => 'show', :id => '10'}, {:controller => 'admin/user', :action => 'list'}],
113       ]
114       p = nil
115       gentime = Benchmark.realtime do
116         n.times do
117         pairs.each {|(a, b)| rs.generate(a, b)}
118         end
119       end
120       
121       puts "\n\nGeneration (RouteSet): (#{(n * 8)} urls)"
122       per_url = gentime / (n * 8)
123       puts "#{per_url * 1000} ms/url"
124       puts "#{1 / per_url} url/s\n\n"
125     end
126   end
128   def test_route_with_colon_first
129     rs.draw do |map|
130       map.connect '/:controller/:action/:id', :action => 'index', :id => nil
131       map.connect ':url', :controller => 'tiny_url', :action => 'translate'
132     end
133   end
135   def test_route_with_regexp_for_controller
136     rs.draw do |map|
137       map.connect ':controller/:admintoken/:action/:id', :controller => /admin\/.+/
138       map.connect ':controller/:action/:id'
139     end
140     assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
141         rs.recognize_path("/admin/user/foo"))
142     assert_equal({:controller => "content", :action => "foo"}, rs.recognize_path("/content/foo"))
143     assert_equal '/admin/user/foo', rs.generate(:controller => "admin/user", :admintoken => "foo", :action => "index")
144     assert_equal '/content/foo', rs.generate(:controller => "content", :action => "foo")
145   end
147   def test_route_with_regexp_and_dot
148     rs.draw do |map|
149       map.connect ':controller/:action/:file',
150                         :controller => /admin|user/,
151                         :action => /upload|download/,
152                         :defaults => {:file => nil},
153                         :requirements => {:file => %r{[^/]+(\.[^/]+)?}}
154     end
155     # Without a file extension
156     assert_equal '/user/download/file',
157       rs.generate(:controller => "user", :action => "download", :file => "file")
158     assert_equal(
159       {:controller => "user", :action => "download", :file => "file"},
160       rs.recognize_path("/user/download/file"))
162     # Now, let's try a file with an extension, really a dot (.)
163     assert_equal '/user/download/file.jpg',
164       rs.generate(
165         :controller => "user", :action => "download", :file => "file.jpg")
166     assert_equal(
167       {:controller => "user", :action => "download", :file => "file.jpg"},
168       rs.recognize_path("/user/download/file.jpg"))
169   end
170   
171   def test_basic_named_route
172     rs.add_named_route :home, '', :controller => 'content', :action => 'list' 
173     x = setup_for_named_route
174     assert_equal("http://named.route.test/",
175                  x.send(:home_url))
176   end
178   def test_basic_named_route_with_relative_url_root
179     rs.add_named_route :home, '', :controller => 'content', :action => 'list' 
180     x = setup_for_named_route
181     x.relative_url_root="/foo"
182     assert_equal("http://named.route.test/foo/",
183                  x.send(:home_url))
184     assert_equal "/foo/", x.send(:home_path)
185   end
187   def test_named_route_with_option
188     rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page'
189     x = setup_for_named_route
190     assert_equal("http://named.route.test/page/new%20stuff",
191                  x.send(:page_url, :title => 'new stuff'))
192   end
194   def test_named_route_with_default
195     rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page', :title => 'AboutPage'
196     x = setup_for_named_route
197     assert_equal("http://named.route.test/page/AboutRails",
198                  x.send(:page_url, :title => "AboutRails"))
200   end
202   def test_named_route_with_nested_controller
203     rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index'
204     x = setup_for_named_route
205     assert_equal("http://named.route.test/admin/user",
206                  x.send(:users_url))
207   end
208   
209   uses_mocha "named route optimisation" do
210     def test_optimised_named_route_call_never_uses_url_for
211       rs.add_named_route :users, 'admin/user', :controller => '/admin/user', :action => 'index'
212       rs.add_named_route :user, 'admin/user/:id', :controller=>'/admin/user', :action=>'show'
213       x = setup_for_named_route
214       x.expects(:url_for).never
215       x.send(:users_url)
216       x.send(:users_path)
217       x.send(:user_url, 2, :foo=>"bar")
218       x.send(:user_path, 3, :bar=>"foo")
219     end
220     
221     def test_optimized_named_route_with_host 
222         rs.add_named_route :pages, 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com' 
223         x = setup_for_named_route 
224         x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => :pages).once
225       x.send(:pages_url)
226     end
227     
228   end
230   def setup_for_named_route
231     klass = Class.new(MockController)
232     rs.install_helpers(klass)
233     klass.new(rs)
234   end
236   def test_named_route_without_hash
237     rs.draw do |map|
238       map.normal ':controller/:action/:id'
239     end
240   end
241      
242   def test_named_route_root
243     rs.draw do |map|
244       map.root :controller => "hello"
245     end                     
246     x = setup_for_named_route       
247     assert_equal("http://named.route.test/", x.send(:root_url))
248     assert_equal("/", x.send(:root_path))
249   end
250   
251   def test_named_route_with_regexps
252     rs.draw do |map|
253       map.article 'page/:year/:month/:day/:title', :controller => 'page', :action => 'show',
254         :year => /\d+/, :month => /\d+/, :day => /\d+/
255       map.connect ':controller/:action/:id'
256     end
257     x = setup_for_named_route
258     # assert_equal(
259     #   {:controller => 'page', :action => 'show', :title => 'hi', :use_route => :article, :only_path => false},
260     #   x.send(:article_url, :title => 'hi')
261     # )
262     assert_equal(
263       "http://named.route.test/page/2005/6/10/hi",
264       x.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6)
265     )
266   end
268   def test_changing_controller
269     assert_equal '/admin/stuff/show/10', rs.generate(
270       {:controller => 'stuff', :action => 'show', :id => 10},
271       {:controller => 'admin/user', :action => 'index'}
272     )
273   end  
275   def test_paths_escaped
276     rs.draw do |map|
277       map.path 'file/*path', :controller => 'content', :action => 'show_file'
278       map.connect ':controller/:action/:id'
279     end
281     # No + to space in URI escaping, only for query params.
282     results = rs.recognize_path "/file/hello+world/how+are+you%3F"
283     assert results, "Recognition should have succeeded"
284     assert_equal ['hello+world', 'how+are+you?'], results[:path]
286     # Use %20 for space instead.
287     results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
288     assert results, "Recognition should have succeeded"
289     assert_equal ['hello world', 'how are you?'], results[:path]
291     results = rs.recognize_path "/file"
292     assert results, "Recognition should have succeeded"
293     assert_equal [], results[:path]
294   end
295   
296   def test_paths_slashes_unescaped_with_ordered_parameters
297     rs.add_named_route :path, '/file/*path', :controller => 'content' 
299     # No / to %2F in URI, only for query params. 
300     x = setup_for_named_route 
301     assert_equal("/file/hello/world", x.send(:path_path, 'hello/world'))
302   end
303   
304   def test_non_controllers_cannot_be_matched
305     rs.draw do |map|
306       map.connect ':controller/:action/:id'
307     end
308     assert_raises(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
309   end
311   def test_paths_do_not_accept_defaults
312     assert_raises(ActionController::RoutingError) do
313       rs.draw do |map|
314         map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => %w(fake default)
315         map.connect ':controller/:action/:id'
316       end
317     end
318     
319     rs.draw do |map|
320       map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => []
321       map.connect ':controller/:action/:id'
322     end
323   end
324   
325   def test_should_list_options_diff_when_routing_requirements_dont_match
326     rs.draw do |map|
327       map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
328     end
329     exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") }
330     assert_match /^post_url failed to generate/, exception.message
331     from_match = exception.message.match(/from \{[^\}]+\}/).to_s
332     assert_match /:bad_param=>"foo"/,   from_match
333     assert_match /:action=>"show"/,     from_match
334     assert_match /:controller=>"post"/, from_match
335     
336     expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s
337     assert_no_match /:bad_param=>"foo"/,   expected_match
338     assert_match    /:action=>"show"/,     expected_match
339     assert_match    /:controller=>"post"/, expected_match
341     diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s
342     assert_match    /:bad_param=>"foo"/,   diff_match
343     assert_no_match /:action=>"show"/,     diff_match
344     assert_no_match /:controller=>"post"/, diff_match
345   end
347   # this specifies the case where your formerly would get a very confusing error message with an empty diff
348   def test_should_have_better_error_message_when_options_diff_is_empty
349     rs.draw do |map|
350       map.content '/content/:query', :controller => 'content', :action => 'show'
351     end
353     exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") }
354     assert_match %r[:action=>"show"], exception.message
355     assert_match %r[:controller=>"content"], exception.message
356     assert_match %r[you may have ambiguous routes, or you may need to supply additional parameters for this route], exception.message
357     assert_match %r[content_url has the following required parameters: \["content", :query\] - are they all satisfied?], exception.message
358   end
359   
360   def test_dynamic_path_allowed
361     rs.draw do |map|
362       map.connect '*path', :controller => 'content', :action => 'show_file'
363     end
365     assert_equal '/pages/boo', rs.generate(:controller => 'content', :action => 'show_file', :path => %w(pages boo))
366   end
368   def test_dynamic_recall_paths_allowed
369     rs.draw do |map|
370       map.connect '*path', :controller => 'content', :action => 'show_file'
371     end
372     
373     recall_path = ActionController::Routing::PathSegment::Result.new(%w(pages boo))
374     assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => recall_path)
375   end
377   def test_backwards
378     rs.draw do |map|
379       map.connect 'page/:id/:action', :controller => 'pages', :action => 'show'
380       map.connect ':controller/:action/:id'
381     end
383     assert_equal '/page/20', rs.generate({:id => 20}, {:controller => 'pages', :action => 'show'})
384     assert_equal '/page/20', rs.generate(:controller => 'pages', :id => 20, :action => 'show')
385     assert_equal '/pages/boo', rs.generate(:controller => 'pages', :action => 'boo')
386   end
388   def test_route_with_fixnum_default
389     rs.draw do |map|
390       map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1
391       map.connect ':controller/:action/:id'
392     end
394     assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page')
395     assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => 1)
396     assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => '1')
397     assert_equal '/page/10', rs.generate(:controller => 'content', :action => 'show_page', :id => 10)
399     assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page"))
400     assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1"))
401     assert_equal({:controller => "content", :action => 'show_page', :id => '10'}, rs.recognize_path("/page/10"))
402   end
404   # For newer revision
405   def test_route_with_text_default
406     rs.draw do |map|
407       map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1
408       map.connect ':controller/:action/:id'
409     end
411     assert_equal '/page/foo', rs.generate(:controller => 'content', :action => 'show_page', :id => 'foo')
412     assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo"))
414     token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian
415     escaped_token = CGI::escape(token)
417     assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token)
418     assert_equal({:controller => "content", :action => 'show_page', :id => token}, rs.recognize_path("/page/#{escaped_token}"))
419   end
420   
421   def test_action_expiry
422     assert_equal '/content', rs.generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
423   end
425   def test_recognition_with_uppercase_controller_name
426     assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/Content"))
427     assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/ConTent/list"))
428     assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/CONTENT/show/10"))
430     # these used to work, before the routes rewrite, but support for this was pulled in the new version...
431     #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/NewsFeed"))
432     #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/News_Feed"))
433   end
434   
435   def test_requirement_should_prevent_optional_id
436     rs.draw do |map|
437       map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
438     end
440     assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10)
441     
442     assert_raises ActionController::RoutingError do
443       rs.generate(:controller => 'post', :action => 'show')
444     end
445   end
446   
447   def test_both_requirement_and_optional
448     rs.draw do |map|
449       map.blog('test/:year', :controller => 'post', :action => 'show',
450         :defaults => { :year => nil },
451         :requirements => { :year => /\d{4}/ }
452       )
453       map.connect ':controller/:action/:id'
454     end
456     assert_equal '/test', rs.generate(:controller => 'post', :action => 'show')
457     assert_equal '/test', rs.generate(:controller => 'post', :action => 'show', :year => nil)
458     
459     x = setup_for_named_route
460     assert_equal("http://named.route.test/test",
461                  x.send(:blog_url))
462   end
463   
464   def test_set_to_nil_forgets
465     rs.draw do |map|
466       map.connect 'pages/:year/:month/:day', :controller => 'content', :action => 'list_pages', :month => nil, :day => nil
467       map.connect ':controller/:action/:id'
468     end
469     
470     assert_equal '/pages/2005',
471       rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005)
472     assert_equal '/pages/2005/6',
473       rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6)
474     assert_equal '/pages/2005/6/12',
475       rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12)
476     
477     assert_equal '/pages/2005/6/4',
478       rs.generate({:day => 4}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
480     assert_equal '/pages/2005/6',
481       rs.generate({:day => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
483     assert_equal '/pages/2005',
484       rs.generate({:day => nil, :month => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
485   end
486   
487   def test_url_with_no_action_specified
488     rs.draw do |map|
489       map.connect '', :controller => 'content'
490       map.connect ':controller/:action/:id'
491     end
492     
493     assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
494     assert_equal '/', rs.generate(:controller => 'content')
495   end
497   def test_named_url_with_no_action_specified
498     rs.draw do |map|
499       map.home '', :controller => 'content'
500       map.connect ':controller/:action/:id'
501     end
502     
503     assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
504     assert_equal '/', rs.generate(:controller => 'content')
505     
506     x = setup_for_named_route
507     assert_equal("http://named.route.test/",
508                  x.send(:home_url))
509   end
510   
511   def test_url_generated_when_forgetting_action
512     [{:controller => 'content', :action => 'index'}, {:controller => 'content'}].each do |hash| 
513       rs.draw do |map|
514         map.home '', hash
515         map.connect ':controller/:action/:id'
516       end
517       assert_equal '/', rs.generate({:action => nil}, {:controller => 'content', :action => 'hello'})
518       assert_equal '/', rs.generate({:controller => 'content'})
519       assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
520     end
521   end
522   
523   def test_named_route_method
524     rs.draw do |map|
525       map.categories 'categories', :controller => 'content', :action => 'categories'
526       map.connect ':controller/:action/:id'
527     end
529     assert_equal '/categories', rs.generate(:controller => 'content', :action => 'categories')
530     assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
531   end
533   def test_named_routes_array
534     test_named_route_method
535     assert_equal [:categories], rs.named_routes.names
536   end
538   def test_nil_defaults
539     rs.draw do |map|
540       map.connect 'journal',
541         :controller => 'content',
542         :action => 'list_journal',
543         :date => nil, :user_id => nil
544       map.connect ':controller/:action/:id'
545     end
547     assert_equal '/journal', rs.generate(:controller => 'content', :action => 'list_journal', :date => nil, :user_id => nil)
548   end
550   def setup_request_method_routes_for(method)
551     @request = ActionController::TestRequest.new
552     @request.env["REQUEST_METHOD"] = method
553     @request.request_uri = "/match"
555     rs.draw do |r|
556       r.connect '/match', :controller => 'books', :action => 'get', :conditions => { :method => :get }
557       r.connect '/match', :controller => 'books', :action => 'post', :conditions => { :method => :post }
558       r.connect '/match', :controller => 'books', :action => 'put', :conditions => { :method => :put }
559       r.connect '/match', :controller => 'books', :action => 'delete', :conditions => { :method => :delete }
560     end
561   end
563   %w(GET POST PUT DELETE).each do |request_method|
564     define_method("test_request_method_recognized_with_#{request_method}") do
565       begin
566         Object.const_set(:BooksController, Class.new(ActionController::Base))
568         setup_request_method_routes_for(request_method)
570         assert_nothing_raised { rs.recognize(@request) }
571         assert_equal request_method.downcase, @request.path_parameters[:action]
572       ensure
573         Object.send(:remove_const, :BooksController) rescue nil
574       end
575     end
576   end
578   def test_subpath_recognized
579     Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
581     rs.draw do |r|
582       r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
583       r.connect '/items/:id/:action', :controller => 'subpath_books'
584       r.connect '/posts/new/:action', :controller => 'subpath_books'
585       r.connect '/posts/:id', :controller => 'subpath_books', :action => "show"
586     end
588     hash = rs.recognize_path "/books/17/edit"
589     assert_not_nil hash
590     assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
591     
592     hash = rs.recognize_path "/items/3/complete"
593     assert_not_nil hash
594     assert_equal %w(subpath_books 3 complete), [hash[:controller], hash[:id], hash[:action]]
595     
596     hash = rs.recognize_path "/posts/new/preview"
597     assert_not_nil hash
598     assert_equal %w(subpath_books preview), [hash[:controller], hash[:action]]
600     hash = rs.recognize_path "/posts/7"
601     assert_not_nil hash
602     assert_equal %w(subpath_books show 7), [hash[:controller], hash[:action], hash[:id]]
603   ensure
604     Object.send(:remove_const, :SubpathBooksController) rescue nil
605   end
607   def test_subpath_generated
608     Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
610     rs.draw do |r|
611       r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
612       r.connect '/items/:id/:action', :controller => 'subpath_books'
613       r.connect '/posts/new/:action', :controller => 'subpath_books'
614     end
616     assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit")
617     assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete")
618     assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview")
619   ensure
620     Object.send(:remove_const, :SubpathBooksController) rescue nil
621   end
622   
623   def test_failed_requirements_raises_exception_with_violated_requirements
624     rs.draw do |r|
625       r.foo_with_requirement 'foos/:id', :controller=>'foos', :requirements=>{:id=>/\d+/}
626     end
627     
628     x = setup_for_named_route
629     assert_raises(ActionController::RoutingError) do 
630       x.send(:foo_with_requirement_url, "I am Against the requirements")
631     end
632   end
635 class SegmentTest < Test::Unit::TestCase
636   
637   def test_first_segment_should_interpolate_for_structure
638     s = ROUTING::Segment.new
639     def s.interpolation_statement(array) 'hello' end
640     assert_equal 'hello', s.continue_string_structure([])
641   end
642   
643   def test_interpolation_statement
644     s = ROUTING::StaticSegment.new
645     s.value = "Hello"
646     assert_equal "Hello", eval(s.interpolation_statement([]))
647     assert_equal "HelloHello", eval(s.interpolation_statement([s]))
648     
649     s2 = ROUTING::StaticSegment.new
650     s2.value = "-"
651     assert_equal "Hello-Hello", eval(s.interpolation_statement([s, s2]))
652     
653     s3 = ROUTING::StaticSegment.new
654     s3.value = "World"
655     assert_equal "Hello-World", eval(s3.interpolation_statement([s, s2]))
656   end
657   
660 class StaticSegmentTest < Test::Unit::TestCase
662   def test_interpolation_chunk_should_respect_raw
663     s = ROUTING::StaticSegment.new
664     s.value = 'Hello World'
665     assert ! s.raw?
666     assert_equal 'Hello%20World', s.interpolation_chunk
668     s.raw = true
669     assert s.raw?
670     assert_equal 'Hello World', s.interpolation_chunk
671   end
673   def test_regexp_chunk_should_escape_specials
674     s = ROUTING::StaticSegment.new
675     
676     s.value = 'Hello*World'
677     assert_equal 'Hello\*World', s.regexp_chunk
678     
679     s.value = 'HelloWorld'
680     assert_equal 'HelloWorld', s.regexp_chunk
681   end
682   
683   def test_regexp_chunk_should_add_question_mark_for_optionals
684     s = ROUTING::StaticSegment.new
685     s.value = "/"
686     s.is_optional = true
687     assert_equal "/?", s.regexp_chunk
688     
689     s.value = "hello"
690     assert_equal "(?:hello)?", s.regexp_chunk
691   end
692   
695 class DynamicSegmentTest < Test::Unit::TestCase
696   
697   def segment
698     unless @segment
699       @segment = ROUTING::DynamicSegment.new
700       @segment.key = :a
701     end
702     @segment
703   end
704   
705   def test_extract_value
706     s = ROUTING::DynamicSegment.new
707     s.key = :a
708     
709     hash = {:a => '10', :b => '20'}
710     assert_equal '10', eval(s.extract_value)
711     
712     hash = {:b => '20'}
713     assert_equal nil, eval(s.extract_value)
714     
715     s.default = '20'
716     assert_equal '20', eval(s.extract_value)
717   end
718   
719   def test_default_local_name
720     assert_equal 'a_value', segment.local_name,
721       "Unexpected name -- all value_check tests will fail!"
722   end
723   
724   def test_presence_value_check
725     a_value = 10
726     assert eval(segment.value_check)
727   end
728   
729   def test_regexp_value_check_rejects_nil
730     segment.regexp = /\d+/
731     a_value = nil
732     assert ! eval(segment.value_check)
733   end
734   
735   def test_optional_regexp_value_check_should_accept_nil
736     segment.regexp = /\d+/
737     segment.is_optional = true
738     a_value = nil
739     assert eval(segment.value_check)
740   end
741   
742   def test_regexp_value_check_rejects_no_match
743     segment.regexp = /\d+/
744     
745     a_value = "Hello20World"
746     assert ! eval(segment.value_check)
747     
748     a_value = "20Hi"
749     assert ! eval(segment.value_check)
750   end
751   
752   def test_regexp_value_check_accepts_match
753     segment.regexp = /\d+/
754     
755     a_value = "30"
756     assert eval(segment.value_check)
757   end
758   
759   def test_value_check_fails_on_nil
760     a_value = nil
761     assert ! eval(segment.value_check)
762   end
763   
764   def test_optional_value_needs_no_check
765     segment.is_optional = true
766     a_value = nil
767     assert_equal nil, segment.value_check
768   end
769   
770   def test_regexp_value_check_should_accept_match_with_default
771     segment.regexp = /\d+/
772     segment.default = '200'
773     
774     a_value = '100'
775     assert eval(segment.value_check)
776   end
777   
778   def test_expiry_should_not_trigger_once_expired
779     expired = true
780     hash = merged = {:a => 2, :b => 3}
781     options = {:b => 3}
782     expire_on = Hash.new { raise 'No!!!' }
783     
784     eval(segment.expiry_statement)
785   rescue RuntimeError
786     flunk "Expiry check should not have occurred!"
787   end
788   
789   def test_expiry_should_occur_according_to_expire_on
790     expired = false
791     hash = merged = {:a => 2, :b => 3}
792     options = {:b => 3}
793     
794     expire_on = {:b => true, :a => false}
795     eval(segment.expiry_statement)
796     assert !expired
797     assert_equal({:a => 2, :b => 3}, hash)
798     
799     expire_on = {:b => true, :a => true}
800     eval(segment.expiry_statement)
801     assert expired
802     assert_equal({:b => 3}, hash)
803   end
804   
805   def test_extraction_code_should_return_on_nil
806     hash = merged = {:b => 3}
807     options = {:b => 3}
808     a_value = nil
809     
810     # Local jump because of return inside eval.
811     assert_raises(LocalJumpError) { eval(segment.extraction_code) }
812   end
813   
814   def test_extraction_code_should_return_on_mismatch
815     segment.regexp = /\d+/
816     hash = merged = {:a => 'Hi', :b => '3'}
817     options = {:b => '3'}
818     a_value = nil
819     
820     # Local jump because of return inside eval.
821     assert_raises(LocalJumpError) { eval(segment.extraction_code) }
822   end
823   
824   def test_extraction_code_should_accept_value_and_set_local
825     hash = merged = {:a => 'Hi', :b => '3'}
826     options = {:b => '3'}
827     a_value = nil
828     expired = true
830     eval(segment.extraction_code)
831     assert_equal 'Hi', a_value
832   end
833   
834   def test_extraction_should_work_without_value_check
835     segment.default = 'hi'
836     hash = merged = {:b => '3'}
837     options = {:b => '3'}
838     a_value = nil
839     expired = true
840     
841     eval(segment.extraction_code)
842     assert_equal 'hi', a_value
843   end
844   
845   def test_extraction_code_should_perform_expiry
846     expired = false
847     hash = merged = {:a => 'Hi', :b => '3'}
848     options = {:b => '3'}
849     expire_on = {:a => true}
850     a_value = nil
851     
852     eval(segment.extraction_code)
853     assert_equal 'Hi', a_value
854     assert expired
855     assert_equal options, hash
856   end
857   
858   def test_interpolation_chunk_should_replace_value
859     a_value = 'Hi'
860     assert_equal a_value, eval(%("#{segment.interpolation_chunk}"))
861   end
862   
863   def test_interpolation_chunk_should_accept_nil
864     a_value = nil
865     assert_equal '', eval(%("#{segment.interpolation_chunk('a_value')}"))
866   end
867   
868   def test_value_regexp_should_be_nil_without_regexp
869     assert_equal nil, segment.value_regexp
870   end
871   
872   def test_value_regexp_should_match_exacly
873     segment.regexp = /\d+/
874     assert_no_match segment.value_regexp, "Hello 10 World"
875     assert_no_match segment.value_regexp, "Hello 10"
876     assert_no_match segment.value_regexp, "10 World"
877     assert_match segment.value_regexp, "10"
878   end
879   
880   def test_regexp_chunk_should_return_string
881     segment.regexp = /\d+/
882     assert_kind_of String, segment.regexp_chunk
883   end
884   
885   def test_build_pattern_non_optional_with_no_captures
886     # Non optioanl
887     a_segment = ROUTING::DynamicSegment.new
888     a_segment.regexp = /\d+/ #number_of_captures is 0
889     assert_equal "(\\d+)stuff", a_segment.build_pattern('stuff')
890   end
892   def test_build_pattern_non_optional_with_captures
893     # Non optioanl
894     a_segment = ROUTING::DynamicSegment.new
895     a_segment.regexp = /(\d+)(.*?)/ #number_of_captures is 2
896     assert_equal "((\\d+)(.*?))stuff", a_segment.build_pattern('stuff')
897   end
899   def test_optionality_implied
900     a_segment = ROUTING::DynamicSegment.new
901     a_segment.key = :id
902     assert a_segment.optionality_implied?
904     a_segment.key = :action
905     assert a_segment.optionality_implied?
906   end
909 class ControllerSegmentTest < Test::Unit::TestCase
910   
911   def test_regexp_should_only_match_possible_controllers
912     ActionController::Routing.with_controllers %w(admin/accounts admin/users account pages) do
913       cs = ROUTING::ControllerSegment.new :controller
914       regexp = %r{\A#{cs.regexp_chunk}\Z}
915       
916       ActionController::Routing.possible_controllers.each do |name|
917         assert_match regexp, name
918         assert_no_match regexp, "#{name}_fake"
919         
920         match = regexp.match name
921         assert_equal name, match[1]
922       end
923     end
924   end
925   
928 uses_mocha 'RouteTest' do
930   class MockController
931     attr_accessor :routes
933     def initialize(routes)
934       self.routes = routes
935     end
937     def url_for(options)
938       only_path = options.delete(:only_path)
939       path = routes.generate(options)
940       only_path ? path : "http://named.route.test#{path}"
941     end
942     
943     def request
944       @request ||= MockRequest.new(:host => "named.route.test", :method => :get)
945     end
946     
947     def relative_url_root=(value)
948       request.relative_url_root=value
949     end
950   end
952   class MockRequest
953     attr_accessor :path, :path_parameters, :host, :subdomains, :domain,
954                   :method, :relative_url_root
955     
956     def initialize(values={})
957       values.each { |key, value| send("#{key}=", value) }
958       if values[:host]
959         subdomain, self.domain = values[:host].split(/\./, 2)
960         self.subdomains = [subdomain]
961       end
962     end
963     
964     def protocol
965       "http://"
966     end
967     
968     def host_with_port
969       (subdomains * '.') + '.' +  domain
970     end
971   end
973 class RouteTest < Test::Unit::TestCase
975   def setup
976     @route = ROUTING::Route.new
977   end
979   def slash_segment(is_optional = false)
980     returning ROUTING::DividerSegment.new('/') do |s|
981       s.is_optional = is_optional
982     end
983   end
984   
985   def default_route
986     unless defined?(@default_route)
987       @default_route = ROUTING::Route.new
988       
989       @default_route.segments << (s = ROUTING::StaticSegment.new)
990       s.value = '/'
991       s.raw = true
992       
993       @default_route.segments << (s = ROUTING::DynamicSegment.new)
994       s.key = :controller
995       
996       @default_route.segments << slash_segment(:optional)
997       @default_route.segments << (s = ROUTING::DynamicSegment.new)
998       s.key = :action
999       s.default = 'index'
1000       s.is_optional = true
1001       
1002       @default_route.segments << slash_segment(:optional)
1003       @default_route.segments << (s = ROUTING::DynamicSegment.new)
1004       s.key = :id
1005       s.is_optional = true
1006       
1007       @default_route.segments << slash_segment(:optional)
1008     end
1009     @default_route
1010   end
1012   def test_default_route_recognition
1013     expected = {:controller => 'accounts', :action => 'show', :id => '10'}
1014     assert_equal expected, default_route.recognize('/accounts/show/10')
1015     assert_equal expected, default_route.recognize('/accounts/show/10/')
1016     
1017     expected[:id] = 'jamis'
1018     assert_equal expected, default_route.recognize('/accounts/show/jamis/')
1019     
1020     expected.delete :id
1021     assert_equal expected, default_route.recognize('/accounts/show')
1022     assert_equal expected, default_route.recognize('/accounts/show/')
1023     
1024     expected[:action] = 'index'
1025     assert_equal expected, default_route.recognize('/accounts/')
1026     assert_equal expected, default_route.recognize('/accounts')
1027     
1028     assert_equal nil, default_route.recognize('/')
1029     assert_equal nil, default_route.recognize('/accounts/how/goood/it/is/to/be/free')
1030   end
1031   
1032   def test_default_route_should_omit_default_action
1033     o = {:controller => 'accounts', :action => 'index'}
1034     assert_equal '/accounts', default_route.generate(o, o, {})
1035   end
1036   
1037   def test_default_route_should_include_default_action_when_id_present
1038     o = {:controller => 'accounts', :action => 'index', :id => '20'}
1039     assert_equal '/accounts/index/20', default_route.generate(o, o, {})
1040   end
1041   
1042   def test_default_route_should_work_with_action_but_no_id
1043     o = {:controller => 'accounts', :action => 'list_all'}
1044     assert_equal '/accounts/list_all', default_route.generate(o, o, {})
1045   end
1046   
1047   def test_default_route_should_uri_escape_pluses
1048     expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' }
1049     assert_equal expected, default_route.recognize('/accounts/show/hello world')
1050     assert_equal expected, default_route.recognize('/accounts/show/hello%20world')
1051     assert_equal '/accounts/show/hello%20world', default_route.generate(expected, expected, {})
1053     expected[:id] = 'hello+world'
1054     assert_equal expected, default_route.recognize('/accounts/show/hello+world')
1055     assert_equal expected, default_route.recognize('/accounts/show/hello%2Bworld')
1056     assert_equal '/accounts/show/hello+world', default_route.generate(expected, expected, {})
1057   end
1059   def test_matches_controller_and_action
1060     # requirement_for should only be called for the action and controller _once_
1061     @route.expects(:requirement_for).with(:controller).times(1).returns('pages')
1062     @route.expects(:requirement_for).with(:action).times(1).returns('show')
1063     
1064     @route.requirements = {:controller => 'pages', :action => 'show'}
1065     assert @route.matches_controller_and_action?('pages', 'show')
1066     assert !@route.matches_controller_and_action?('not_pages', 'show')
1067     assert !@route.matches_controller_and_action?('pages', 'not_show')
1068   end
1069     
1070   def test_parameter_shell
1071     page_url = ROUTING::Route.new
1072     page_url.requirements = {:controller => 'pages', :action => 'show', :id => /\d+/}
1073     assert_equal({:controller => 'pages', :action => 'show'}, page_url.parameter_shell)
1074   end
1076   def test_defaults
1077     route = ROUTING::RouteBuilder.new.build '/users/:id.:format', :controller => "users", :action => "show", :format => "html"
1078     assert_equal(
1079       { :controller => "users", :action => "show", :format => "html" },
1080       route.defaults)
1081   end
1082   
1083   def test_builder_complains_without_controller
1084     assert_raises(ArgumentError) do
1085       ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index"
1086     end
1087   end
1089   def test_significant_keys_for_default_route
1090     keys = default_route.significant_keys.sort_by {|k| k.to_s }
1091     assert_equal [:action, :controller, :id], keys
1092   end
1093   
1094   def test_significant_keys
1095     user_url = ROUTING::Route.new
1096     user_url.segments << (s = ROUTING::StaticSegment.new)
1097     s.value = '/'
1098     s.raw = true
1099     
1100     user_url.segments << (s = ROUTING::StaticSegment.new)
1101     s.value = 'user'
1102     
1103     user_url.segments << (s = ROUTING::StaticSegment.new)
1104     s.value = '/'
1105     s.raw = true
1106     s.is_optional = true
1107     
1108     user_url.segments << (s = ROUTING::DynamicSegment.new)
1109     s.key = :user
1110     
1111     user_url.segments << (s = ROUTING::StaticSegment.new)
1112     s.value = '/'
1113     s.raw = true
1114     s.is_optional = true
1115     
1116     user_url.requirements = {:controller => 'users', :action => 'show'}
1117     
1118     keys = user_url.significant_keys.sort_by { |k| k.to_s }
1119     assert_equal [:action, :controller, :user], keys
1120   end
1122   def test_build_empty_query_string
1123     assert_equal '', @route.build_query_string({})
1124   end
1126   def test_build_query_string_with_nil_value
1127     assert_equal '', @route.build_query_string({:x => nil})
1128   end
1130   def test_simple_build_query_string
1131     assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => '1', :y => '2'))
1132   end
1134   def test_convert_ints_build_query_string
1135     assert_equal '?x=1&y=2', order_query_string(@route.build_query_string(:x => 1, :y => 2))
1136   end
1138   def test_escape_spaces_build_query_string
1139     assert_equal '?x=hello+world&y=goodbye+world', order_query_string(@route.build_query_string(:x => 'hello world', :y => 'goodbye world'))
1140   end
1142   def test_expand_array_build_query_string
1143     assert_equal '?x%5B%5D=1&x%5B%5D=2', order_query_string(@route.build_query_string(:x => [1, 2]))
1144   end
1146   def test_escape_spaces_build_query_string_selected_keys
1147     assert_equal '?x=hello+world', order_query_string(@route.build_query_string({:x => 'hello world', :y => 'goodbye world'}, [:x]))
1148   end
1149   
1150   private
1151     def order_query_string(qs)
1152       '?' + qs[1..-1].split('&').sort.join('&')
1153     end
1156 end # uses_mocha
1158 class RouteBuilderTest < Test::Unit::TestCase
1160   def builder
1161     @builder ||= ROUTING::RouteBuilder.new
1162   end
1164   def build(path, options)
1165     builder.build(path, options)
1166   end
1168   def test_options_should_not_be_modified
1169     requirements1 = { :id => /\w+/, :controller => /(?:[a-z](?:-?[a-z]+)*)/ }
1170     requirements2 = requirements1.dup
1172     assert_equal requirements1, requirements2
1174     with_options(:controller => 'folder',
1175                  :requirements => requirements2) do |m|
1176       m.build 'folders/new', :action => 'new'
1177     end
1179     assert_equal requirements1, requirements2
1180   end
1182   def test_segment_for_static
1183     segment, rest = builder.segment_for 'ulysses'
1184     assert_equal '', rest
1185     assert_kind_of ROUTING::StaticSegment, segment
1186     assert_equal 'ulysses', segment.value
1187   end
1188   
1189   def test_segment_for_action
1190     segment, rest = builder.segment_for ':action'
1191     assert_equal '', rest
1192     assert_kind_of ROUTING::DynamicSegment, segment
1193     assert_equal :action, segment.key
1194     assert_equal 'index', segment.default
1195   end
1196   
1197   def test_segment_for_dynamic
1198     segment, rest = builder.segment_for ':login'
1199     assert_equal '', rest
1200     assert_kind_of ROUTING::DynamicSegment, segment
1201     assert_equal :login, segment.key
1202     assert_equal nil, segment.default
1203     assert ! segment.optional?
1204   end
1205   
1206   def test_segment_for_with_rest
1207     segment, rest = builder.segment_for ':login/:action'
1208     assert_equal :login, segment.key
1209     assert_equal '/:action', rest
1210     segment, rest = builder.segment_for rest
1211     assert_equal '/', segment.value
1212     assert_equal ':action', rest
1213     segment, rest = builder.segment_for rest
1214     assert_equal :action, segment.key
1215     assert_equal '', rest
1216   end
1217   
1218   def test_segments_for
1219     segments = builder.segments_for_route_path '/:controller/:action/:id'
1220     
1221     assert_kind_of ROUTING::DividerSegment, segments[0]
1222     assert_equal '/', segments[2].value
1223     
1224     assert_kind_of ROUTING::DynamicSegment, segments[1]
1225     assert_equal :controller, segments[1].key
1226     
1227     assert_kind_of ROUTING::DividerSegment, segments[2]
1228     assert_equal '/', segments[2].value
1229     
1230     assert_kind_of ROUTING::DynamicSegment, segments[3]
1231     assert_equal :action, segments[3].key
1232     
1233     assert_kind_of ROUTING::DividerSegment, segments[4]
1234     assert_equal '/', segments[4].value
1235     
1236     assert_kind_of ROUTING::DynamicSegment, segments[5]
1237     assert_equal :id, segments[5].key
1238   end
1239   
1240   def test_segment_for_action
1241     s, r = builder.segment_for(':action/something/else')
1242     assert_equal '/something/else', r
1243     assert_equal :action, s.key
1244   end
1245   
1246   def test_action_default_should_not_trigger_on_prefix
1247     s, r = builder.segment_for ':action_name/something/else'
1248     assert_equal '/something/else', r
1249     assert_equal :action_name, s.key
1250     assert_equal nil, s.default
1251   end
1252   
1253   def test_divide_route_options
1254     segments = builder.segments_for_route_path '/cars/:action/:person/:car/'
1255     defaults, requirements = builder.divide_route_options(segments,
1256       :action => 'buy', :person => /\w+/, :car => /\w+/,
1257       :defaults => {:person => nil, :car => nil}
1258     )
1259     
1260     assert_equal({:action => 'buy', :person => nil, :car => nil}, defaults)
1261     assert_equal({:person => /\w+/, :car => /\w+/}, requirements)
1262   end
1263   
1264   def test_assign_route_options
1265     segments = builder.segments_for_route_path '/cars/:action/:person/:car/'
1266     defaults = {:action => 'buy', :person => nil, :car => nil}
1267     requirements = {:person => /\w+/, :car => /\w+/}
1268     
1269     route_requirements = builder.assign_route_options(segments, defaults, requirements)
1270     assert_equal({}, route_requirements)
1271     
1272     assert_equal :action, segments[3].key
1273     assert_equal 'buy', segments[3].default
1274     
1275     assert_equal :person, segments[5].key
1276     assert_equal %r/\w+/, segments[5].regexp
1277     assert segments[5].optional?
1278     
1279     assert_equal :car, segments[7].key
1280     assert_equal %r/\w+/, segments[7].regexp
1281     assert segments[7].optional?
1282   end
1283   
1284   def test_assign_route_options_with_anchor_chars
1285     segments = builder.segments_for_route_path '/cars/:action/:person/:car/'
1286     defaults = {:action => 'buy', :person => nil, :car => nil}
1287     requirements = {:person => /\w+/, :car => /^\w+$/}
1288     
1289     assert_raises ArgumentError do
1290       route_requirements = builder.assign_route_options(segments, defaults, requirements)
1291     end
1292     
1293     requirements[:car] = /[^\/]+/
1294     route_requirements = builder.assign_route_options(segments, defaults, requirements)
1295   end
1296   
1298   def test_optional_segments_preceding_required_segments
1299     segments = builder.segments_for_route_path '/cars/:action/:person/:car/'
1300     defaults = {:action => 'buy', :person => nil, :car => "model-t"}
1301     assert builder.assign_route_options(segments, defaults, {}).empty?
1302     
1303     0.upto(1) { |i| assert !segments[i].optional?, "segment #{i} is optional and it shouldn't be" }
1304     assert segments[2].optional?
1305     
1306     assert_equal nil, builder.warn_output # should only warn on the :person segment
1307   end
1308   
1309   def test_segmentation_of_dot_path
1310     segments = builder.segments_for_route_path '/books/:action.rss'
1311     assert builder.assign_route_options(segments, {}, {}).empty?
1312     assert_equal 6, segments.length # "/", "books", "/", ":action", ".", "rss"
1313     assert !segments.any? { |seg| seg.optional? }
1314   end
1315   
1316   def test_segmentation_of_dynamic_dot_path
1317     segments = builder.segments_for_route_path '/books/:action.:format'
1318     assert builder.assign_route_options(segments, {}, {}).empty?
1319     assert_equal 6, segments.length # "/", "books", "/", ":action", ".", ":format"
1320     assert !segments.any? { |seg| seg.optional? }
1321     assert_kind_of ROUTING::DynamicSegment, segments.last
1322   end
1323   
1324   def test_assignment_of_default_options
1325     segments = builder.segments_for_route_path '/:controller/:action/:id/'
1326     action, id = segments[-4], segments[-2]
1327     
1328     assert_equal :action, action.key
1329     assert_equal :id, id.key
1330     assert ! action.optional?
1331     assert ! id.optional?
1332     
1333     builder.assign_default_route_options(segments)
1334     
1335     assert_equal 'index', action.default
1336     assert action.optional?
1337     assert id.optional?
1338   end
1339   
1340   def test_assignment_of_default_options_respects_existing_defaults
1341     segments = builder.segments_for_route_path '/:controller/:action/:id/'
1342     action, id = segments[-4], segments[-2]
1343     
1344     assert_equal :action, action.key
1345     assert_equal :id, id.key
1346     action.default = 'show'
1347     action.is_optional = true
1348     
1349     id.default = 'Welcome'
1350     id.is_optional = true
1351     
1352     builder.assign_default_route_options(segments)
1353     
1354     assert_equal 'show', action.default
1355     assert action.optional?
1356     assert_equal 'Welcome', id.default
1357     assert id.optional?
1358   end
1359   
1360   def test_assignment_of_default_options_respects_regexps
1361     segments = builder.segments_for_route_path '/:controller/:action/:id/'
1362     action = segments[-4]
1363     
1364     assert_equal :action, action.key
1365     action.regexp = /show|in/ # Use 'in' to check partial matches
1366     
1367     builder.assign_default_route_options(segments)
1368     
1369     assert_equal nil, action.default
1370     assert ! action.optional?
1371   end
1372   
1373   def test_assignment_of_is_optional_when_default
1374     segments = builder.segments_for_route_path '/books/:action.rss'
1375     assert_equal segments[3].key, :action
1376     segments[3].default = 'changes'
1377     builder.ensure_required_segments(segments)
1378     assert ! segments[3].optional?
1379   end
1380   
1381   def test_is_optional_is_assigned_to_default_segments
1382     segments = builder.segments_for_route_path '/books/:action'
1383     builder.assign_route_options(segments, {:action => 'index'}, {})
1384     
1385     assert_equal segments[3].key, :action
1386     assert segments[3].optional?
1387     assert_kind_of ROUTING::DividerSegment, segments[2]
1388     assert segments[2].optional?
1389   end
1390   
1391   # XXX is optional not being set right?
1392   # /blah/:defaulted_segment <-- is the second slash optional? it should be.
1393   
1394   def test_route_build
1395     ActionController::Routing.with_controllers %w(users pages) do
1396       r = builder.build '/:controller/:action/:id/', :action => nil
1397       
1398       [0, 2, 4].each do |i|
1399         assert_kind_of ROUTING::DividerSegment, r.segments[i]
1400         assert_equal '/', r.segments[i].value
1401         assert r.segments[i].optional? if i > 1
1402       end
1403       
1404       assert_kind_of ROUTING::DynamicSegment, r.segments[1]
1405       assert_equal :controller, r.segments[1].key
1406       assert_equal nil, r.segments[1].default
1407       
1408       assert_kind_of ROUTING::DynamicSegment, r.segments[3]
1409       assert_equal :action, r.segments[3].key
1410       assert_equal 'index', r.segments[3].default
1411       
1412       assert_kind_of ROUTING::DynamicSegment, r.segments[5]
1413       assert_equal :id, r.segments[5].key
1414       assert r.segments[5].optional?
1415     end
1416   end
1417   
1418   def test_slashes_are_implied
1419     routes = [
1420       builder.build('/:controller/:action/:id/', :action => nil),
1421       builder.build('/:controller/:action/:id', :action => nil),
1422       builder.build(':controller/:action/:id', :action => nil),
1423       builder.build('/:controller/:action/:id/', :action => nil)
1424     ]
1425     expected = routes.first.segments.length
1426     routes.each_with_index do |route, i|
1427       found = route.segments.length
1428       assert_equal expected, found, "Route #{i + 1} has #{found} segments, expected #{expected}"
1429     end
1430   end
1431   
1437 class RouteSetTest < Test::Unit::TestCase
1439   def set
1440     @set ||= ROUTING::RouteSet.new
1441   end
1443   def request
1444     @request ||= MockRequest.new(:host => "named.routes.test", :method => :get)
1445   end
1447   def test_generate_extras
1448     set.draw { |m| m.connect ':controller/:action/:id' }
1449     path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
1450     assert_equal "/foo/bar/15", path
1451     assert_equal %w(that this), extras.map(&:to_s).sort
1452   end
1454   def test_extra_keys
1455     set.draw { |m| m.connect ':controller/:action/:id' }
1456     extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
1457     assert_equal %w(that this), extras.map(&:to_s).sort
1458   end
1459   
1460   def test_generate_extras_not_first
1461     set.draw do |map| 
1462       map.connect ':controller/:action/:id.:format'
1463       map.connect ':controller/:action/:id'
1464     end    
1465     path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
1466     assert_equal "/foo/bar/15", path
1467     assert_equal %w(that this), extras.map(&:to_s).sort
1468   end
1469   
1470   def test_generate_not_first
1471     set.draw do |map| 
1472       map.connect ':controller/:action/:id.:format'
1473       map.connect ':controller/:action/:id'
1474     end    
1475     assert_equal "/foo/bar/15?this=hello", set.generate(:controller => "foo", :action => "bar", :id => 15, :this => "hello")
1476   end
1477   
1478   def test_extra_keys_not_first
1479     set.draw do |map| 
1480       map.connect ':controller/:action/:id.:format'
1481       map.connect ':controller/:action/:id'
1482     end
1483     extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
1484     assert_equal %w(that this), extras.map(&:to_s).sort
1485   end   
1487   def test_draw
1488     assert_equal 0, set.routes.size
1489     set.draw do |map|
1490       map.connect '/hello/world', :controller => 'a', :action => 'b'
1491     end
1492     assert_equal 1, set.routes.size
1493   end
1494   
1495   def test_named_draw
1496     assert_equal 0, set.routes.size
1497     set.draw do |map|
1498       map.hello '/hello/world', :controller => 'a', :action => 'b'
1499     end
1500     assert_equal 1, set.routes.size
1501     assert_equal set.routes.first, set.named_routes[:hello]
1502   end
1503   
1504   def test_later_named_routes_take_precedence
1505     set.draw do |map|
1506       map.hello '/hello/world', :controller => 'a', :action => 'b'
1507       map.hello '/hello', :controller => 'a', :action => 'b'
1508     end
1509     assert_equal set.routes.last, set.named_routes[:hello]
1510   end
1512   def setup_named_route_test
1513     set.draw do |map|
1514       map.show '/people/:id', :controller => 'people', :action => 'show'
1515       map.index '/people', :controller => 'people', :action => 'index'
1516       map.multi '/people/go/:foo/:bar/joe/:id', :controller => 'people', :action => 'multi'
1517       map.users '/admin/users', :controller => 'admin/users', :action => 'index'
1518     end
1520     klass = Class.new(MockController)
1521     set.install_helpers(klass)
1522     klass.new(set)
1523   end
1525   def test_named_route_hash_access_method
1526     controller = setup_named_route_test
1528     assert_equal(
1529       { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => false },
1530       controller.send(:hash_for_show_url, :id => 5))
1532     assert_equal(
1533       { :controller => 'people', :action => 'index', :use_route => :index, :only_path => false },
1534       controller.send(:hash_for_index_url))
1535     
1536     assert_equal(
1537       { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => true },
1538       controller.send(:hash_for_show_path, :id => 5)
1539     )
1540   end
1542   def test_named_route_url_method
1543     controller = setup_named_route_test
1544     
1545     assert_equal "http://named.route.test/people/5", controller.send(:show_url, :id => 5)
1546     assert_equal "/people/5", controller.send(:show_path, :id => 5)
1547     
1548     assert_equal "http://named.route.test/people", controller.send(:index_url)
1549     assert_equal "/people", controller.send(:index_path)
1551     assert_equal "http://named.route.test/admin/users", controller.send(:users_url)
1552     assert_equal '/admin/users', controller.send(:users_path)
1553     assert_equal '/admin/users', set.generate(controller.send(:hash_for_users_url), {:controller => 'users', :action => 'index'})
1554   end
1556   def test_namd_route_url_method_with_ordered_parameters
1557     controller = setup_named_route_test
1558     assert_equal "http://named.route.test/people/go/7/hello/joe/5",
1559       controller.send(:multi_url, 7, "hello", 5)
1560   end
1562   def test_named_route_url_method_with_ordered_parameters_and_hash
1563     controller = setup_named_route_test
1564     assert_equal "http://named.route.test/people/go/7/hello/joe/5?baz=bar",
1565       controller.send(:multi_url, 7, "hello", 5, :baz => "bar")
1566   end
1567   
1568   def test_named_route_url_method_with_no_positional_arguments
1569     controller = setup_named_route_test
1570     assert_equal "http://named.route.test/people?baz=bar",
1571       controller.send(:index_url, :baz => "bar")
1572   end
1573   
1574   def test_draw_default_route
1575     ActionController::Routing.with_controllers(['users']) do
1576       set.draw do |map|
1577         map.connect '/:controller/:action/:id'
1578       end
1580       assert_equal 1, set.routes.size
1581       route = set.routes.first
1583       assert route.segments.last.optional?
1585       assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10)
1586       assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10)
1588       assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10'))
1589       assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10/'))
1590     end
1591   end
1593   def test_draw_default_route_with_default_controller
1594     ActionController::Routing.with_controllers(['users']) do
1595       set.draw do |map|
1596         map.connect '/:controller/:action/:id', :controller => 'users'
1597       end      
1598       assert_equal({:controller => 'users', :action => 'index'}, set.recognize_path('/'))
1599     end
1600   end
1602   def test_route_with_parameter_shell
1603     ActionController::Routing.with_controllers(['users', 'pages']) do
1604       set.draw do |map|
1605         map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
1606         map.connect '/:controller/:action/:id'
1607       end
1609       assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages'))
1610       assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages/index'))
1611       assert_equal({:controller => 'pages', :action => 'list'}, set.recognize_path('/pages/list'))
1613       assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/pages/show/10'))
1614       assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10'))
1615     end
1616   end
1618   def test_route_requirements_with_anchor_chars_are_invalid
1619     assert_raises ArgumentError do
1620       set.draw do |map|
1621         map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /^\d+/
1622       end
1623     end
1624     assert_raises ArgumentError do
1625       set.draw do |map|
1626         map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/
1627       end
1628     end
1629     assert_raises ArgumentError do
1630       set.draw do |map|
1631         map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/
1632       end
1633     end
1634     assert_raises ArgumentError do
1635       set.draw do |map|
1636         map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/
1637       end
1638     end
1639     assert_raises ArgumentError do
1640       set.draw do |map|
1641         map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/
1642       end
1643     end
1644     assert_nothing_raised do
1645       set.draw do |map|
1646         map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/
1647       end
1648       assert_raises ActionController::RoutingError do
1649         set.generate :controller => 'pages', :action => 'show', :id => 10
1650       end
1651     end
1652   end
1653   
1654   def test_non_path_route_requirements_match_all
1655     set.draw do |map|
1656       map.connect 'page/37s', :controller => 'pages', :action => 'show', :name => /(jamis|david)/
1657     end
1658     assert_equal '/page/37s', set.generate(:controller => 'pages', :action => 'show', :name => 'jamis')
1659     assert_raises ActionController::RoutingError do
1660       set.generate(:controller => 'pages', :action => 'show', :name => 'not_jamis')
1661     end
1662     assert_raises ActionController::RoutingError do
1663       set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david')
1664     end
1665   end
1666   
1667   def test_recognize_with_encoded_id_and_regex
1668     set.draw do |map|
1669       map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /[a-zA-Z0-9\+]+/
1670     end
1672     assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10'))
1673     assert_equal({:controller => 'pages', :action => 'show', :id => 'hello+world'}, set.recognize_path('/page/hello+world'))
1674   end
1676   def test_recognize_with_conditions
1677     Object.const_set(:PeopleController, Class.new)
1679     set.draw do |map|
1680       map.with_options(:controller => "people") do |people|
1681         people.people  "/people",     :action => "index",   :conditions => { :method => :get }
1682         people.connect "/people",     :action => "create",  :conditions => { :method => :post }
1683         people.person  "/people/:id", :action => "show",    :conditions => { :method => :get }
1684         people.connect "/people/:id", :action => "update",  :conditions => { :method => :put }
1685         people.connect "/people/:id", :action => "destroy", :conditions => { :method => :delete }
1686       end
1687     end
1689     request.path = "/people"
1690     request.method = :get
1691     assert_nothing_raised { set.recognize(request) }
1692     assert_equal("index", request.path_parameters[:action])
1693     
1694     request.method = :post
1695     assert_nothing_raised { set.recognize(request) }
1696     assert_equal("create", request.path_parameters[:action])
1697     
1698     request.method = :put
1699     assert_nothing_raised { set.recognize(request) }
1700     assert_equal("update", request.path_parameters[:action])
1702     begin
1703       request.method = :bacon
1704       set.recognize(request)
1705       flunk 'Should have raised NotImplemented'
1706     rescue ActionController::NotImplemented => e
1707       assert_equal [:get, :post, :put, :delete], e.allowed_methods
1708     end
1710     request.path = "/people/5"
1711     request.method = :get
1712     assert_nothing_raised { set.recognize(request) }
1713     assert_equal("show", request.path_parameters[:action])
1714     assert_equal("5", request.path_parameters[:id])
1716     request.method = :put
1717     assert_nothing_raised { set.recognize(request) }
1718     assert_equal("update", request.path_parameters[:action])
1719     assert_equal("5", request.path_parameters[:id])
1721     request.method = :delete
1722     assert_nothing_raised { set.recognize(request) }
1723     assert_equal("destroy", request.path_parameters[:action])
1724     assert_equal("5", request.path_parameters[:id])
1726     begin
1727       request.method = :post
1728       set.recognize(request)
1729       flunk 'Should have raised MethodNotAllowed'
1730     rescue ActionController::MethodNotAllowed => e
1731       assert_equal [:get, :put, :delete], e.allowed_methods
1732     end
1734   ensure
1735     Object.send(:remove_const, :PeopleController)
1736   end
1737   
1738   def test_typo_recognition
1739     Object.const_set(:ArticlesController, Class.new)
1741     set.draw do |map|
1742       map.connect 'articles/:year/:month/:day/:title',
1743              :controller => 'articles', :action => 'permalink',
1744              :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
1745     end
1746   
1747     request.path = "/articles/2005/11/05/a-very-interesting-article"
1748     request.method = :get
1749     assert_nothing_raised { set.recognize(request) }
1750     assert_equal("permalink", request.path_parameters[:action])
1751     assert_equal("2005", request.path_parameters[:year])
1752     assert_equal("11", request.path_parameters[:month])
1753     assert_equal("05", request.path_parameters[:day])
1754     assert_equal("a-very-interesting-article", request.path_parameters[:title])
1755     
1756   ensure
1757     Object.send(:remove_const, :ArticlesController)
1758   end
1760   def test_routing_traversal_does_not_load_extra_classes
1761     assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
1762     set.draw do |map|
1763       map.connect '/profile', :controller => 'profile'
1764     end
1766     request.path = '/profile'
1768     set.recognize(request) rescue nil
1769     
1770     assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
1771   end
1773   def test_recognize_with_conditions_and_format
1774     Object.const_set(:PeopleController, Class.new)
1776     set.draw do |map|
1777       map.with_options(:controller => "people") do |people|
1778         people.person  "/people/:id", :action => "show",    :conditions => { :method => :get }
1779         people.connect "/people/:id", :action => "update",  :conditions => { :method => :put }
1780         people.connect "/people/:id.:_format", :action => "show", :conditions => { :method => :get }
1781       end
1782     end
1784     request.path = "/people/5"
1785     request.method = :get
1786     assert_nothing_raised { set.recognize(request) }
1787     assert_equal("show", request.path_parameters[:action])
1788     assert_equal("5", request.path_parameters[:id])
1790     request.method = :put
1791     assert_nothing_raised { set.recognize(request) }
1792     assert_equal("update", request.path_parameters[:action])
1794     request.path = "/people/5.png"
1795     request.method = :get
1796     assert_nothing_raised { set.recognize(request) }
1797     assert_equal("show", request.path_parameters[:action])
1798     assert_equal("5", request.path_parameters[:id])
1799     assert_equal("png", request.path_parameters[:_format])
1800   ensure
1801     Object.send(:remove_const, :PeopleController)
1802   end
1804   def test_generate_with_default_action
1805     set.draw do |map|
1806       map.connect "/people", :controller => "people"
1807       map.connect "/people/list", :controller => "people", :action => "list"
1808     end
1810     url = set.generate(:controller => "people", :action => "list")
1811     assert_equal "/people/list", url
1812   end
1813   
1814   def test_root_map
1815     Object.const_set(:PeopleController, Class.new)
1817     set.draw { |map| map.root :controller => "people" }
1819     request.path = ""
1820     request.method = :get
1821     assert_nothing_raised { set.recognize(request) }
1822     assert_equal("people", request.path_parameters[:controller])
1823     assert_equal("index", request.path_parameters[:action])
1824   ensure
1825     Object.send(:remove_const, :PeopleController)
1826   end
1827   
1828   
1829   def test_namespace
1830     Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
1832     set.draw do |map| 
1833       
1834       map.namespace 'api' do |api|
1835         api.route 'inventory', :controller => "products", :action => 'inventory'
1836       end
1837       
1838     end
1840     request.path = "/api/inventory"
1841     request.method = :get
1842     assert_nothing_raised { set.recognize(request) }
1843     assert_equal("api/products", request.path_parameters[:controller])
1844     assert_equal("inventory", request.path_parameters[:action])
1845   ensure
1846     Object.send(:remove_const, :Api)
1847   end
1848   
1850   def test_namespaced_root_map
1851     Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
1853     set.draw do |map| 
1854       
1855       map.namespace 'api' do |api|
1856         api.root :controller => "products"       
1857       end
1858       
1859     end
1861     request.path = "/api"
1862     request.method = :get
1863     assert_nothing_raised { set.recognize(request) }
1864     assert_equal("api/products", request.path_parameters[:controller])
1865     assert_equal("index", request.path_parameters[:action])
1866   ensure
1867     Object.send(:remove_const, :Api)
1868   end
1870   def test_generate_finds_best_fit
1871     set.draw do |map|
1872       map.connect "/people", :controller => "people", :action => "index"
1873       map.connect "/ws/people", :controller => "people", :action => "index", :ws => true
1874     end
1876     url = set.generate(:controller => "people", :action => "index", :ws => true)
1877     assert_equal "/ws/people", url
1878   end
1880   def test_generate_changes_controller_module
1881     set.draw { |map| map.connect ':controller/:action/:id' }
1882     current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
1883     url = set.generate({:controller => "foo/bar", :action => "baz", :id => 7}, current)
1884     assert_equal "/foo/bar/baz/7", url
1885   end
1887   def test_id_is_not_impossibly_sticky
1888     set.draw do |map|
1889       map.connect 'foo/:number', :controller => "people", :action => "index"
1890       map.connect ':controller/:action/:id'
1891     end
1893     url = set.generate({:controller => "people", :action => "index", :number => 3},
1894       {:controller => "people", :action => "index", :id => "21"})
1895     assert_equal "/foo/3", url
1896   end
1898   def test_id_is_sticky_when_it_ought_to_be
1899     set.draw do |map|
1900       map.connect ':controller/:id/:action'
1901     end
1903     url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"})
1904     assert_equal "/people/7/destroy", url
1905   end
1907   def test_use_static_path_when_possible
1908     set.draw do |map|
1909       map.connect 'about', :controller => "welcome", :action => "about"
1910       map.connect ':controller/:action/:id'
1911     end
1913     url = set.generate({:controller => "welcome", :action => "about"},
1914       {:controller => "welcome", :action => "get", :id => "7"})
1915     assert_equal "/about", url
1916   end
1918   def test_generate
1919     set.draw { |map| map.connect ':controller/:action/:id' }
1921     args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1922     assert_equal "/foo/bar/7?x=y", set.generate(args)
1923     assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
1924     assert_equal [:x], set.extra_keys(args)
1925   end
1927   def test_named_routes_are_never_relative_to_modules
1928     set.draw do |map|
1929       map.connect "/connection/manage/:action", :controller => 'connection/manage'
1930       map.connect "/connection/connection", :controller => "connection/connection"
1931       map.family_connection "/connection", :controller => "connection"
1932     end
1934     url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'})
1935     assert_equal "/connection/connection", url
1937     url = set.generate({:use_route => :family_connection, :controller => "connection"}, {:controller => 'connection/manage'})
1938     assert_equal "/connection", url
1939   end
1940   
1941   def test_action_left_off_when_id_is_recalled
1942     set.draw do |map|
1943       map.connect ':controller/:action/:id'
1944     end
1945     assert_equal '/post', set.generate(
1946       {:controller => 'post', :action => 'index'},
1947       {:controller => 'post', :action => 'show', :id => '10'}
1948     )
1949   end
1950   
1951   def test_query_params_will_be_shown_when_recalled
1952     set.draw do |map|
1953       map.connect 'show_post/:parameter', :controller => 'post', :action => 'show'
1954       map.connect ':controller/:action/:id'
1955     end
1956     assert_equal '/post/edit?parameter=1', set.generate(
1957       {:action => 'edit', :parameter => 1},
1958       {:controller => 'post', :action => 'show', :parameter => 1}
1959     )
1960   end
1962   def test_expiry_determination_should_consider_values_with_to_param
1963     set.draw { |map| map.connect 'projects/:project_id/:controller/:action' }
1964     assert_equal '/projects/1/post/show', set.generate(
1965       {:action => 'show', :project_id => 1},
1966       {:controller => 'post', :action => 'show', :project_id => '1'})
1967   end
1969   def test_generate_all
1970     set.draw do |map|
1971       map.connect 'show_post/:id', :controller => 'post', :action => 'show'
1972       map.connect ':controller/:action/:id'
1973     end
1974     all = set.generate(
1975       {:action => 'show', :id => 10, :generate_all => true},
1976       {:controller => 'post', :action => 'show'}
1977     )
1978     assert_equal 2, all.length
1979     assert_equal '/show_post/10', all.first
1980     assert_equal '/post/show/10', all.last
1981   end
1982   
1985 class RoutingTest < Test::Unit::TestCase
1986   
1987   def test_possible_controllers
1988     true_controller_paths = ActionController::Routing.controller_paths
1990     ActionController::Routing.use_controllers! nil
1992     silence_warnings do
1993       Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures')
1994     end
1996     ActionController::Routing.controller_paths = [
1997       RAILS_ROOT, RAILS_ROOT + '/app/controllers', RAILS_ROOT + '/vendor/plugins/bad_plugin/lib'
1998     ]
1999     
2000     assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
2001   ensure
2002     if true_controller_paths
2003       ActionController::Routing.controller_paths = true_controller_paths
2004     end
2005     ActionController::Routing.use_controllers! nil
2006     Object.send(:remove_const, :RAILS_ROOT) rescue nil
2007   end
2008   
2009   def test_possible_controllers_are_reset_on_each_load
2010     true_possible_controllers = ActionController::Routing.possible_controllers
2011     true_controller_paths = ActionController::Routing.controller_paths
2012     
2013     ActionController::Routing.use_controllers! nil
2014     root = File.dirname(__FILE__) + '/controller_fixtures'
2015     
2016     ActionController::Routing.controller_paths = []
2017     assert_equal [], ActionController::Routing.possible_controllers
2018     
2019     ActionController::Routing::Routes.load!
2020     ActionController::Routing.controller_paths = [
2021       root, root + '/app/controllers', root + '/vendor/plugins/bad_plugin/lib'
2022     ]
2023     
2024     assert_equal ["admin/user", "plugin", "user"], ActionController::Routing.possible_controllers.sort
2025   ensure
2026     ActionController::Routing.controller_paths = true_controller_paths
2027     ActionController::Routing.use_controllers! true_possible_controllers
2028     Object.send(:remove_const, :RAILS_ROOT) rescue nil
2029     
2030     ActionController::Routing::Routes.clear!
2031     ActionController::Routing::Routes.load_routes!
2032   end
2033   
2034   def test_with_controllers
2035     c = %w(admin/accounts admin/users account pages)
2036     ActionController::Routing.with_controllers c do
2037       assert_equal c, ActionController::Routing.possible_controllers
2038     end
2039   end
2041   def test_normalize_unix_paths
2042     load_paths = %w(. config/../app/controllers config/../app//helpers script/../config/../vendor/rails/actionpack/lib vendor/rails/railties/builtin/rails_info app/models lib script/../config/../foo/bar/../../app/models)
2043     paths = ActionController::Routing.normalize_paths(load_paths)
2044     assert_equal %w(vendor/rails/railties/builtin/rails_info vendor/rails/actionpack/lib app/controllers app/helpers app/models lib .), paths
2045   end
2047   def test_normalize_windows_paths
2048     load_paths = %w(. config\\..\\app\\controllers config\\..\\app\\\\helpers script\\..\\config\\..\\vendor\\rails\\actionpack\\lib vendor\\rails\\railties\\builtin\\rails_info app\\models lib script\\..\\config\\..\\foo\\bar\\..\\..\\app\\models)
2049     paths = ActionController::Routing.normalize_paths(load_paths)
2050     assert_equal %w(vendor\\rails\\railties\\builtin\\rails_info vendor\\rails\\actionpack\\lib app\\controllers app\\helpers app\\models lib .), paths
2051   end
2052   
2053   def test_routing_helper_module
2054     assert_kind_of Module, ActionController::Routing::Helpers
2055     
2056     h = ActionController::Routing::Helpers
2057     c = Class.new
2058     assert ! c.ancestors.include?(h)
2059     ActionController::Routing::Routes.install_helpers c
2060     assert c.ancestors.include?(h)
2061   end
2062   
2065 uses_mocha 'route loading' do
2066   class RouteLoadingTest < Test::Unit::TestCase
2068     def setup
2069       routes.instance_variable_set '@routes_last_modified', nil
2070       silence_warnings { Object.const_set :RAILS_ROOT, '.' }
2072       @stat = stub_everything
2073     end
2075     def teardown
2076       Object.send :remove_const, :RAILS_ROOT
2077     end
2079     def test_load
2080       File.expects(:stat).returns(@stat)
2081       routes.expects(:load).with(regexp_matches(/routes\.rb$/))
2083       routes.reload
2084     end
2086     def test_no_reload_when_not_modified
2087       @stat.expects(:mtime).times(2).returns(1)
2088       File.expects(:stat).times(2).returns(@stat)
2089       routes.expects(:load).with(regexp_matches(/routes\.rb$/)).at_most_once
2091       2.times { routes.reload }
2092     end
2094     def test_reload_when_modified
2095       @stat.expects(:mtime).at_least(2).returns(1, 2)
2096       File.expects(:stat).at_least(2).returns(@stat)
2097       routes.expects(:load).with(regexp_matches(/routes\.rb$/)).times(2)
2099       2.times { routes.reload }
2100     end
2102     def test_bang_forces_reload
2103       @stat.expects(:mtime).at_least(2).returns(1)
2104       File.expects(:stat).at_least(2).returns(@stat)
2105       routes.expects(:load).with(regexp_matches(/routes\.rb$/)).times(2)
2107       2.times { routes.reload! }
2108     end
2110     def test_adding_inflections_forces_reload
2111       Inflector::Inflections.instance.expects(:uncountable).with('equipment')
2112       routes.expects(:reload!)
2114       Inflector.inflections { |inflect| inflect.uncountable('equipment') }
2115     end
2117     private
2118     def routes
2119       ActionController::Routing::Routes
2120     end
2122   end