actionpack 2.0.2 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (74) hide show
  1. data/CHANGELOG +45 -0
  2. data/Rakefile +5 -3
  3. data/lib/action_controller.rb +0 -0
  4. data/lib/action_controller/assertions/response_assertions.rb +6 -2
  5. data/lib/action_controller/assertions/routing_assertions.rb +5 -2
  6. data/lib/action_controller/base.rb +4 -3
  7. data/lib/action_controller/cgi_ext/cookie.rb +1 -1
  8. data/lib/action_controller/filters.rb +5 -3
  9. data/lib/action_controller/http_authentication.rb +2 -4
  10. data/lib/action_controller/integration.rb +3 -2
  11. data/lib/action_controller/layout.rb +14 -15
  12. data/lib/action_controller/mime_type.rb +4 -1
  13. data/lib/action_controller/polymorphic_routes.rb +90 -15
  14. data/lib/action_controller/record_identifier.rb +4 -4
  15. data/lib/action_controller/request.rb +29 -14
  16. data/lib/action_controller/request_forgery_protection.rb +41 -34
  17. data/lib/action_controller/request_profiler.rb +16 -6
  18. data/lib/action_controller/response.rb +0 -0
  19. data/lib/action_controller/routing.rb +3 -3
  20. data/lib/action_controller/session/active_record_store.rb +7 -8
  21. data/lib/action_controller/session/cookie_store.rb +2 -3
  22. data/lib/action_controller/templates/rescues/_trace.erb +5 -5
  23. data/lib/action_controller/test_case.rb +24 -4
  24. data/lib/action_controller/test_process.rb +3 -3
  25. data/lib/action_controller/url_rewriter.rb +29 -28
  26. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +2 -2
  27. data/lib/action_controller/verification.rb +73 -57
  28. data/lib/action_pack/version.rb +1 -1
  29. data/lib/action_view/base.rb +24 -6
  30. data/lib/action_view/helpers/active_record_helper.rb +1 -1
  31. data/lib/action_view/helpers/asset_tag_helper.rb +12 -6
  32. data/lib/action_view/helpers/atom_feed_helper.rb +21 -17
  33. data/lib/action_view/helpers/date_helper.rb +6 -6
  34. data/lib/action_view/helpers/form_helper.rb +3 -2
  35. data/lib/action_view/helpers/form_options_helper.rb +12 -1
  36. data/lib/action_view/helpers/form_tag_helper.rb +18 -0
  37. data/lib/action_view/helpers/number_helper.rb +1 -1
  38. data/lib/action_view/helpers/prototype_helper.rb +1 -1
  39. data/lib/action_view/helpers/text_helper.rb +1 -1
  40. data/lib/action_view/helpers/url_helper.rb +5 -9
  41. data/lib/action_view/template_error.rb +11 -4
  42. data/test/activerecord/active_record_store_test.rb +1 -1
  43. data/test/activerecord/fixtures_test.rb +24 -0
  44. data/test/controller/action_pack_assertions_test.rb +37 -2
  45. data/test/controller/base_test.rb +4 -1
  46. data/test/controller/cgi_test.rb +4 -3
  47. data/test/controller/filters_test.rb +4 -7
  48. data/test/controller/html-scanner/sanitizer_test.rb +7 -1
  49. data/test/controller/integration_test.rb +0 -1
  50. data/test/controller/mime_type_test.rb +5 -0
  51. data/test/controller/new_render_test.rb +25 -2
  52. data/test/controller/polymorphic_routes_test.rb +106 -75
  53. data/test/controller/redirect_test.rb +11 -0
  54. data/test/controller/render_test.rb +19 -0
  55. data/test/controller/request_forgery_protection_test.rb +9 -0
  56. data/test/controller/request_test.rb +33 -5
  57. data/test/controller/routing_test.rb +4 -4
  58. data/test/controller/session/cookie_store_test.rb +0 -0
  59. data/test/controller/test_test.rb +43 -1
  60. data/test/controller/url_rewriter_test.rb +34 -4
  61. data/test/fixtures/layouts/block_with_layout.erb +3 -0
  62. data/test/fixtures/layouts/partial_with_layout.erb +3 -0
  63. data/test/template/asset_tag_helper_test.rb +17 -13
  64. data/test/template/atom_feed_helper_test.rb +52 -2
  65. data/test/template/compiled_templates_test.rb +5 -1
  66. data/test/template/date_helper_test.rb +1 -1
  67. data/test/template/deprecate_ivars_test.rb +51 -0
  68. data/test/template/form_options_helper_test.rb +29 -0
  69. data/test/template/form_tag_helper_test.rb +18 -0
  70. data/test/template/number_helper_test.rb +1 -0
  71. data/test/template/text_helper_test.rb +32 -14
  72. data/test/template/url_helper_test.rb +1 -1
  73. data/test/testing_sandbox.rb +8 -4
  74. metadata +9 -4
@@ -114,6 +114,24 @@ module ActionView
114
114
  tag :input, { "type" => "text", "name" => name, "id" => name, "value" => value }.update(options.stringify_keys)
115
115
  end
116
116
 
117
+ # Creates a label field
118
+ #
119
+ # ==== Options
120
+ # * Creates standard HTML attributes for the tag.
121
+ #
122
+ # ==== Examples
123
+ # label_tag 'name'
124
+ # # => <label for="name">Name</label>
125
+ #
126
+ # label_tag 'name', 'Your name'
127
+ # # => <label for="name">Your Name</label>
128
+ #
129
+ # label_tag 'name', nil, :class => 'small_label'
130
+ # # => <label for="name" class="small_label">Name</label>
131
+ def label_tag(name, text = nil, options = {})
132
+ content_tag :label, text || name.humanize, { "for" => name }.update(options.stringify_keys)
133
+ end
134
+
117
135
  # Creates a hidden form input field used to transmit data that would be lost due to HTTP's statelessness or
118
136
  # data that should be hidden from the user.
119
137
  #
@@ -170,7 +170,7 @@ module ActionView
170
170
  when size < 1.gigabyte; "%.#{precision}f MB" % (size / 1.0.megabyte)
171
171
  when size < 1.terabyte; "%.#{precision}f GB" % (size / 1.0.gigabyte)
172
172
  else "%.#{precision}f TB" % (size / 1.0.terabyte)
173
- end.sub(/([0-9])\.?0+ /, '\1 ' )
173
+ end.sub(/([0-9]\.\d*?)0+ /, '\1 ' ).sub(/\. /,' ')
174
174
  rescue
175
175
  nil
176
176
  end
@@ -1019,7 +1019,7 @@ module ActionView
1019
1019
  js_options['parameters'] = options[:with]
1020
1020
  end
1021
1021
 
1022
- if protect_against_forgery?
1022
+ if protect_against_forgery? && !options[:form]
1023
1023
  if js_options['parameters']
1024
1024
  js_options['parameters'] << " + '&"
1025
1025
  else
@@ -436,7 +436,7 @@ module ActionView
436
436
  [-\w]+ # subdomain or domain
437
437
  (?:\.[-\w]+)* # remaining subdomains or domain
438
438
  (?::\d+)? # port
439
- (?:/(?:(?:[~\w\+@%-]|(?:[,.;:][^\s$]))+)?)* # path
439
+ (?:/(?:(?:[~\w\+@%=-]|(?:[,.;:][^\s$]))+)?)* # path
440
440
  (?:\?[\w\+@%&=.;-]+)? # query string
441
441
  (?:\#[\w\-]*)? # trailing anchor
442
442
  )
@@ -389,9 +389,8 @@ module ActionView
389
389
  email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.has_key?("replace_dot")
390
390
 
391
391
  if encode == "javascript"
392
- tmp = "document.write('#{content_tag("a", name || email_address, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');"
393
- for i in 0...tmp.length
394
- string << sprintf("%%%x",tmp[i])
392
+ "document.write('#{content_tag("a", name || email_address, html_options.merge({ "href" => "mailto:"+email_address+extras }))}');".each_byte do |c|
393
+ string << sprintf("%%%x", c)
395
394
  end
396
395
  "<script type=\"#{Mime::JS}\">eval(unescape('#{string}'))</script>"
397
396
  elsif encode == "hex"
@@ -403,12 +402,9 @@ module ActionView
403
402
  protocol = 'mailto:'
404
403
  protocol.each_byte { |c| string << sprintf("&#%d;", c) }
405
404
 
406
- for i in 0...email_address.length
407
- if email_address[i,1] =~ /\w/
408
- string << sprintf("%%%x",email_address[i])
409
- else
410
- string << email_address[i,1]
411
- end
405
+ email_address.each_byte do |c|
406
+ char = c.chr
407
+ string << (char =~ /\w/ ? sprintf("%%%x", c) : char)
412
408
  end
413
409
  content_tag "a", name || email_address_encoded, html_options.merge({ "href" => "#{string}#{extras}" })
414
410
  else
@@ -10,6 +10,7 @@ module ActionView
10
10
  @base_path, @assigns, @source, @original_exception =
11
11
  base_path, assigns.dup, source, original_exception
12
12
  @file_path = file_path
13
+ @backtrace = compute_backtrace
13
14
  end
14
15
 
15
16
  def message
@@ -72,14 +73,20 @@ module ActionView
72
73
  "#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
73
74
  end
74
75
 
76
+ # don't do anything nontrivial here. Any raised exception from here becomes fatal
77
+ # (and can't be rescued).
75
78
  def backtrace
76
- [
77
- "#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
78
- clean_backtrace.join("\n ")
79
- ]
79
+ @backtrace
80
80
  end
81
81
 
82
82
  private
83
+ def compute_backtrace
84
+ [
85
+ "#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
86
+ clean_backtrace.join("\n ")
87
+ ]
88
+ end
89
+
83
90
  def strip_base_path(path)
84
91
  stripped_path = File.expand_path(path).gsub(@base_path, "")
85
92
  stripped_path.gsub!(/^#{Regexp.escape File.expand_path(RAILS_ROOT)}/, '') if defined?(RAILS_ROOT)
@@ -66,7 +66,7 @@ class ActiveRecordStoreTest < ActiveRecordTestCase
66
66
 
67
67
  def test_save_unloaded_session
68
68
  c = session_class.connection
69
- bogus_class = c.quote(Base64.encode64("\004\010o:\vBlammo\000"))
69
+ bogus_class = c.quote(ActiveSupport::Base64.encode64("\004\010o:\vBlammo\000"))
70
70
  c.insert("INSERT INTO #{session_class.table_name} ('#{session_id_column}', 'data') VALUES ('abcdefghijklmnop', #{bogus_class})")
71
71
 
72
72
  sess = session_class.find_by_session_id('abcdefghijklmnop')
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/../active_record_unit'
2
+ require "action_controller/test_case"
3
+
4
+ class ActionController::TestCase
5
+ self.fixture_path = File.dirname(__FILE__) + '/../fixtures'
6
+ self.use_transactional_fixtures = false
7
+ end
8
+
9
+ class DeveloperController < ActionController::Base
10
+ end
11
+
12
+ class DeveloperControllerTest < ActionController::TestCase
13
+ fixtures :developers
14
+
15
+ def setup
16
+ @david = developers(:david)
17
+ end
18
+
19
+ def test_should_have_loaded_fixtures
20
+ assert_kind_of(Developer, @david)
21
+ assert_kind_of(Developer, developers(:jamis))
22
+ assert_equal(@developers.size, Developer.count)
23
+ end
24
+ end
@@ -124,6 +124,18 @@ class ActionPackAssertionsController < ActionController::Base
124
124
  def rescue_action(e) raise; end
125
125
  end
126
126
 
127
+ # Used to test that assert_response includes the exception message
128
+ # in the failure message when an action raises and assert_response
129
+ # is expecting something other than an error.
130
+ class AssertResponseWithUnexpectedErrorController < ActionController::Base
131
+ def index
132
+ raise 'FAIL'
133
+ end
134
+ end
135
+
136
+ class UserController < ActionController::Base
137
+ end
138
+
127
139
  module Admin
128
140
  class InnerModuleController < ActionController::Base
129
141
  def index
@@ -161,7 +173,7 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
161
173
  # let's get this party started
162
174
  def setup
163
175
  ActionController::Routing::Routes.reload
164
- ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module content admin/user))
176
+ ActionController::Routing.use_controllers!(%w(action_pack_assertions admin/inner_module user content admin/user))
165
177
  @controller = ActionPackAssertionsController.new
166
178
  @request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
167
179
  end
@@ -255,7 +267,7 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
255
267
  assert_redirected_to admin_inner_module_path
256
268
  end
257
269
  end
258
-
270
+
259
271
  def test_assert_redirected_to_top_level_named_route_from_nested_controller
260
272
  with_routing do |set|
261
273
  set.draw do |map|
@@ -269,6 +281,20 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
269
281
  end
270
282
  end
271
283
 
284
+
285
+ def test_assert_redirected_to_top_level_named_route_with_same_controller_name_in_both_namespaces
286
+ with_routing do |set|
287
+ set.draw do |map|
288
+ # this controller exists in the admin namespace as well which is the only difference from previous test
289
+ map.top_level '/user/:id', :controller => 'user', :action => 'index'
290
+ map.connect ':controller/:action/:id'
291
+ end
292
+ @controller = Admin::InnerModuleController.new
293
+ process :redirect_to_top_level_named_route
294
+ assert_redirected_to "/user/foo"
295
+ end
296
+ end
297
+
272
298
  # -- standard request/response object testing --------------------------------
273
299
 
274
300
  # make sure that the template objects exist
@@ -465,6 +491,15 @@ class ActionPackAssertionsControllerTest < Test::Unit::TestCase
465
491
  rescue Test::Unit::AssertionFailedError => e
466
492
  end
467
493
  end
494
+
495
+ def test_assert_response_uses_exception_message
496
+ @controller = AssertResponseWithUnexpectedErrorController.new
497
+ get :index
498
+ assert_response :success
499
+ flunk 'Expected non-success response'
500
+ rescue Test::Unit::AssertionFailedError => e
501
+ assert e.message.include?('FAIL')
502
+ end
468
503
  end
469
504
 
470
505
  class ActionPackHeaderTest < Test::Unit::TestCase
@@ -87,7 +87,10 @@ class ControllerInstanceTests < Test::Unit::TestCase
87
87
  # Mocha adds some public instance methods to Object that would be
88
88
  # considered actions, so explicitly hide_action them.
89
89
  def hide_mocha_methods_from_controller(controller)
90
- mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify, :__metaclass__, :__is_a__]
90
+ mocha_methods = [
91
+ :expects, :mocha, :mocha_inspect, :reset_mocha, :stubba_object,
92
+ :stubba_method, :stubs, :verify, :__metaclass__, :__is_a__, :to_matcher,
93
+ ]
91
94
  controller.class.send!(:hide_action, *mocha_methods)
92
95
  end
93
96
  end
@@ -4,8 +4,9 @@ require 'action_controller/cgi_process'
4
4
  class BaseCgiTest < Test::Unit::TestCase
5
5
  def setup
6
6
  @request_hash = {"HTTP_MAX_FORWARDS"=>"10", "SERVER_NAME"=>"glu.ttono.us:8007", "FCGI_ROLE"=>"RESPONDER", "HTTP_X_FORWARDED_HOST"=>"glu.ttono.us", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1", "PATH_INFO"=>"", "HTTP_ACCEPT_LANGUAGE"=>"en", "HTTP_HOST"=>"glu.ttono.us:8007", "SERVER_PROTOCOL"=>"HTTP/1.1", "REDIRECT_URI"=>"/dispatch.fcgi", "SCRIPT_NAME"=>"/dispatch.fcgi", "SERVER_ADDR"=>"207.7.108.53", "REMOTE_ADDR"=>"207.7.108.53", "SERVER_SOFTWARE"=>"lighttpd/1.4.5", "HTTP_COOKIE"=>"_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes", "HTTP_X_FORWARDED_SERVER"=>"glu.ttono.us", "REQUEST_URI"=>"/admin", "DOCUMENT_ROOT"=>"/home/kevinc/sites/typo/public", "SERVER_PORT"=>"8007", "QUERY_STRING"=>"", "REMOTE_PORT"=>"63137", "GATEWAY_INTERFACE"=>"CGI/1.1", "HTTP_X_FORWARDED_FOR"=>"65.88.180.234", "HTTP_ACCEPT"=>"*/*", "SCRIPT_FILENAME"=>"/home/kevinc/sites/typo/public/dispatch.fcgi", "REDIRECT_STATUS"=>"200", "REQUEST_METHOD"=>"GET"}
7
- # cookie as returned by some Nokia phone browsers (no space after semicolon separator)
8
- @alt_cookie_fmt_request_hash = {"HTTP_COOKIE"=>"_session_id=c84ace84796670c052c6ceb2451fb0f2;is_admin=yes"}
7
+ # some Nokia phone browsers omit the space after the semicolon separator.
8
+ # some developers have grown accustomed to using comma in cookie values.
9
+ @alt_cookie_fmt_request_hash = {"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}
9
10
  @fake_cgi = Struct.new(:env_table).new(@request_hash)
10
11
  @request = ActionController::CgiRequest.new(@fake_cgi)
11
12
  end
@@ -76,7 +77,7 @@ class CgiRequestTest < BaseCgiTest
76
77
  assert_equal ["yes"], cookies["is_admin"], cookies.inspect
77
78
 
78
79
  alt_cookies = CGI::Cookie::parse(@alt_cookie_fmt_request_hash["HTTP_COOKIE"]);
79
- assert_equal ["c84ace84796670c052c6ceb2451fb0f2"], alt_cookies["_session_id"], alt_cookies.inspect
80
+ assert_equal ["c84ace847,96670c052c6ceb2451fb0f2"], alt_cookies["_session_id"], alt_cookies.inspect
80
81
  assert_equal ["yes"], alt_cookies["is_admin"], alt_cookies.inspect
81
82
  end
82
83
  end
@@ -696,10 +696,6 @@ class ControllerWithProcFilter < PostsController
696
696
  end
697
697
  end
698
698
 
699
- class ControllerWithWrongFilterType < PostsController
700
- around_filter lambda { yield }, :only => :no_raise
701
- end
702
-
703
699
  class ControllerWithNestedFilters < ControllerWithSymbolAsFilter
704
700
  around_filter :raise_before, :raise_after, :without_exception, :only => :raises_both
705
701
  end
@@ -746,14 +742,15 @@ class YieldingAroundFiltersTest < Test::Unit::TestCase
746
742
  assert_equal 1, ControllerWithFilterClass.filter_chain.size
747
743
  assert_equal 1, ControllerWithFilterInstance.filter_chain.size
748
744
  assert_equal 3, ControllerWithSymbolAsFilter.filter_chain.size
749
- assert_equal 1, ControllerWithWrongFilterType.filter_chain.size
750
745
  assert_equal 6, ControllerWithNestedFilters.filter_chain.size
751
746
  assert_equal 4, ControllerWithAllTypesOfFilters.filter_chain.size
752
747
  end
753
748
 
754
749
  def test_wrong_filter_type
755
- assert_raise(ActionController::ActionControllerError) do
756
- test_process(ControllerWithWrongFilterType,'no_raise')
750
+ assert_raise ArgumentError do
751
+ Class.new PostsController do
752
+ around_filter lambda { yield }
753
+ end
757
754
  end
758
755
  end
759
756
 
@@ -203,6 +203,12 @@ class SanitizerTest < Test::Unit::TestCase
203
203
  assert_equal expected, sanitize_css(raw)
204
204
  end
205
205
 
206
+ def test_should_sanitize_with_trailing_space
207
+ raw = "display:block; "
208
+ expected = "display: block;"
209
+ assert_equal expected, sanitize_css(raw)
210
+ end
211
+
206
212
  def test_should_sanitize_xul_style_attributes
207
213
  raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss'))
208
214
  assert_equal '', sanitize_css(raw)
@@ -247,4 +253,4 @@ protected
247
253
  def sanitize_css(input)
248
254
  (@sanitizer ||= HTML::WhiteListSanitizer.new).sanitize_css(input)
249
255
  end
250
- end
256
+ end
@@ -1,6 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/../abstract_unit'
2
2
 
3
- $:.unshift File.dirname(__FILE__) + '/../../../railties/lib'
4
3
  require 'action_controller/integration'
5
4
 
6
5
  uses_mocha 'integration' do
@@ -39,6 +39,11 @@ class MimeTypeTest < Test::Unit::TestCase
39
39
  Mime.module_eval { remove_const :GIF if const_defined?(:GIF) }
40
40
  end
41
41
 
42
+ def test_type_should_be_equal_to_symbol
43
+ assert_equal Mime::HTML, 'application/xhtml+xml'
44
+ assert_equal Mime::HTML, :html
45
+ end
46
+
42
47
  def test_type_convenience_methods
43
48
  types = [:html, :xml, :png, :pdf, :yaml, :url_encoded_form]
44
49
  types.each do |type|
@@ -361,10 +361,18 @@ class NewRenderTestController < ActionController::Base
361
361
  render :action => "calling_partial_with_layout"
362
362
  end
363
363
 
364
+ def render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout
365
+ render :action => "calling_partial_with_layout"
366
+ end
367
+
364
368
  def render_using_layout_around_block
365
369
  render :action => "using_layout_around_block"
366
370
  end
367
371
 
372
+ def render_using_layout_around_block_in_main_layout_and_within_content_for_layout
373
+ render :action => "using_layout_around_block"
374
+ end
375
+
368
376
  def rescue_action(e) raise end
369
377
 
370
378
  private
@@ -387,6 +395,10 @@ class NewRenderTestController < ActionController::Base
387
395
  "layouts/builder"
388
396
  when "action_talk_to_layout", "layout_overriding_layout"
389
397
  "layouts/talk_from_action"
398
+ when "render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout"
399
+ "layouts/partial_with_layout"
400
+ when "render_using_layout_around_block_in_main_layout_and_within_content_for_layout"
401
+ "layouts/block_with_layout"
390
402
  end
391
403
  end
392
404
  end
@@ -824,9 +836,20 @@ EOS
824
836
  get :render_call_to_partial_with_layout
825
837
  assert_equal "Before (David)\nInside from partial (David)\nAfter", @response.body
826
838
  end
827
-
839
+
840
+ def test_render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout
841
+ get :render_call_to_partial_with_layout_in_main_layout_and_within_content_for_layout
842
+ assert_equal "Before (Anthony)\nInside from partial (Anthony)\nAfter\nBefore (David)\nInside from partial (David)\nAfter\nBefore (Ramm)\nInside from partial (Ramm)\nAfter", @response.body
843
+ end
844
+
828
845
  def test_using_layout_around_block
829
- get :using_layout_around_block
846
+ get :render_using_layout_around_block
830
847
  assert_equal "Before (David)\nInside from block\nAfter", @response.body
831
848
  end
849
+
850
+ def test_using_layout_around_block_in_main_layout_and_within_content_for_layout
851
+ get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout
852
+ assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body
853
+ end
854
+
832
855
  end
@@ -5,94 +5,125 @@ class Article
5
5
  def save; @id = 1 end
6
6
  def new_record?; @id.nil? end
7
7
  def name
8
- @id.nil? ? 'new post' : "post ##{@id}"
8
+ model = self.class.name.downcase
9
+ @id.nil? ? "new #{model}" : "#{model} ##{@id}"
9
10
  end
10
11
  end
11
12
 
12
- class Comment
13
- attr_reader :id
13
+ class Comment < Article
14
14
  def post_id; 1 end
15
- def save; @id = 1 end
16
- def new_record?; @id.nil? end
17
- def name
18
- @id.nil? ? 'new comment' : "comment ##{@id}"
19
- end
20
15
  end
21
16
 
17
+ class Tag < Article
18
+ def comment_id; 1 end
19
+ end
20
+
21
+ # TODO: test nested models
22
22
  class Comment::Nested < Comment; end
23
23
 
24
- class Test::Unit::TestCase
25
- protected
26
- def articles_url
27
- 'http://www.example.com/articles'
28
- end
29
- alias_method :new_article_url, :articles_url
30
-
31
- def article_url(article)
32
- "http://www.example.com/articles/#{article.id}"
33
- end
24
+ uses_mocha 'polymorphic URL helpers' do
25
+ class PolymorphicRoutesTest < Test::Unit::TestCase
34
26
 
35
- def article_comments_url(article)
36
- "http://www.example.com/articles/#{article.id}/comments"
37
- end
38
-
39
- def article_comment_url(article, comment)
40
- "http://www.example.com/articles/#{article.id}/comments/#{comment.id}"
41
- end
42
-
43
- def admin_articles_url
44
- "http://www.example.com/admin/articles"
45
- end
46
- alias_method :new_admin_article_url, :admin_articles_url
47
-
48
- def admin_article_url(article)
49
- "http://www.example.com/admin/articles/#{article.id}"
50
- end
51
-
52
- def admin_article_comments_url(article)
53
- "http://www.example.com/admin/articles/#{article.id}/comments"
54
- end
27
+ include ActionController::PolymorphicRoutes
28
+
29
+ def setup
30
+ @article = Article.new
31
+ @comment = Comment.new
32
+ end
55
33
 
56
- def admin_article_comment_url(article, comment)
57
- "http://www.example.com/admin/test/articles/#{article.id}/comments/#{comment.id}"
58
- end
59
- end
34
+ def test_with_record
35
+ @article.save
36
+ expects(:article_url).with(@article)
37
+ polymorphic_url(@article)
38
+ end
60
39
 
40
+ def test_with_new_record
41
+ expects(:articles_url).with()
42
+ @article.expects(:new_record?).returns(true)
43
+ polymorphic_url(@article)
44
+ end
61
45
 
62
- class PolymorphicRoutesTest < Test::Unit::TestCase
63
- include ActionController::PolymorphicRoutes
46
+ def test_with_record_and_action
47
+ expects(:new_article_url).with()
48
+ @article.expects(:new_record?).never
49
+ polymorphic_url(@article, :action => 'new')
50
+ end
64
51
 
65
- def setup
66
- @article = Article.new
67
- @comment = Comment.new
68
- end
69
-
70
- def test_with_record
71
- assert_equal(articles_url, polymorphic_url(@article, :action => 'new'))
72
- assert_equal(articles_url, polymorphic_url(@article))
73
- @article.save
74
- assert_equal(article_url(@article), polymorphic_url(@article))
75
- end
76
-
77
- # TODO: Needs to be updated to correctly know about whether the object is in a hash or not
78
- def xtest_with_hash
79
- @article.save
80
- assert_equal(article_url(@article), polymorphic_url(:id => @article))
81
- end
52
+ def test_url_helper_prefixed_with_new
53
+ expects(:new_article_url).with()
54
+ new_polymorphic_url(@article)
55
+ end
56
+
57
+ def test_url_helper_prefixed_with_edit
58
+ @article.save
59
+ expects(:edit_article_url).with(@article)
60
+ edit_polymorphic_url(@article)
61
+ end
62
+
63
+ def test_formatted_url_helper
64
+ expects(:formatted_article_url).with(@article, :pdf)
65
+ formatted_polymorphic_url([@article, :pdf])
66
+ end
67
+
68
+ # TODO: should this work?
69
+ def xtest_format_option
70
+ @article.save
71
+ expects(:article_url).with(@article, :format => :pdf)
72
+ polymorphic_url(@article, :format => :pdf)
73
+ end
74
+
75
+ def test_with_nested
76
+ @comment.save
77
+ expects(:article_comment_url).with(@article, @comment)
78
+ polymorphic_url([@article, @comment])
79
+ end
80
+
81
+ def test_with_nested_unsaved
82
+ expects(:article_comments_url).with(@article)
83
+ polymorphic_url([@article, @comment])
84
+ end
85
+
86
+ def test_new_with_array_and_namespace
87
+ expects(:new_admin_article_url).with()
88
+ polymorphic_url([:admin, @article], :action => 'new')
89
+ end
90
+
91
+ def test_unsaved_with_array_and_namespace
92
+ expects(:admin_articles_url).with()
93
+ polymorphic_url([:admin, @article])
94
+ end
95
+
96
+ def test_nested_unsaved_with_array_and_namespace
97
+ @article.save
98
+ expects(:admin_article_url).with(@article)
99
+ polymorphic_url([:admin, @article])
100
+ expects(:admin_article_comments_url).with(@article)
101
+ polymorphic_url([:admin, @article, @comment])
102
+ end
103
+
104
+ def test_nested_with_array_and_namespace
105
+ @comment.save
106
+ expects(:admin_article_comment_url).with(@article, @comment)
107
+ polymorphic_url([:admin, @article, @comment])
108
+
109
+ # a ridiculously long named route tests correct ordering of namespaces and nesting:
110
+ @tag = Tag.new
111
+ @tag.save
112
+ expects(:site_admin_article_comment_tag_url).with(@article, @comment, @tag)
113
+ polymorphic_url([:site, :admin, @article, @comment, @tag])
114
+ end
115
+
116
+ # TODO: Needs to be updated to correctly know about whether the object is in a hash or not
117
+ def xtest_with_hash
118
+ expects(:article_url).with(@article)
119
+ @article.save
120
+ polymorphic_url(:id => @article)
121
+ end
122
+
123
+ def test_polymorphic_path_accepts_options
124
+ expects(:new_article_path).with()
125
+ polymorphic_path(@article, :action => :new)
126
+ end
82
127
 
83
- def test_with_array
84
- assert_equal(article_comments_url(@article), polymorphic_url([@article, @comment]))
85
- @comment.save
86
- assert_equal(article_comment_url(@article, @comment), polymorphic_url([@article, @comment]))
87
- end
88
-
89
- def test_with_array_and_namespace
90
- assert_equal(admin_articles_url, polymorphic_url([:admin, @article], :action => 'new'))
91
- assert_equal(admin_articles_url, polymorphic_url([:admin, @article]))
92
- @article.save
93
- assert_equal(admin_article_url(@article), polymorphic_url([:admin, @article]))
94
- assert_equal(admin_article_comments_url(@article), polymorphic_url([:admin, @article, @comment]))
95
- @comment.save
96
- assert_equal(admin_article_comment_url(@article, @comment), polymorphic_url([:admin, @article, @comment]))
97
128
  end
98
129
  end