actionpack 1.12.5 → 1.13.0

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 (179) hide show
  1. data/CHANGELOG +517 -15
  2. data/MIT-LICENSE +1 -1
  3. data/README +18 -20
  4. data/Rakefile +7 -4
  5. data/examples/address_book_controller.rb +3 -3
  6. data/examples/blog_controller.cgi +3 -3
  7. data/examples/debate_controller.cgi +5 -5
  8. data/lib/action_controller.rb +2 -2
  9. data/lib/action_controller/assertions.rb +73 -311
  10. data/lib/action_controller/{deprecated_assertions.rb → assertions/deprecated_assertions.rb} +32 -8
  11. data/lib/action_controller/assertions/dom_assertions.rb +25 -0
  12. data/lib/action_controller/assertions/model_assertions.rb +12 -0
  13. data/lib/action_controller/assertions/response_assertions.rb +140 -0
  14. data/lib/action_controller/assertions/routing_assertions.rb +82 -0
  15. data/lib/action_controller/assertions/selector_assertions.rb +571 -0
  16. data/lib/action_controller/assertions/tag_assertions.rb +117 -0
  17. data/lib/action_controller/base.rb +334 -163
  18. data/lib/action_controller/benchmarking.rb +3 -6
  19. data/lib/action_controller/caching.rb +83 -22
  20. data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -7
  21. data/lib/action_controller/cgi_ext/cgi_methods.rb +167 -173
  22. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +43 -22
  23. data/lib/action_controller/cgi_process.rb +50 -27
  24. data/lib/action_controller/components.rb +21 -25
  25. data/lib/action_controller/cookies.rb +10 -9
  26. data/lib/action_controller/{dependencies.rb → deprecated_dependencies.rb} +9 -27
  27. data/lib/action_controller/filters.rb +448 -225
  28. data/lib/action_controller/flash.rb +24 -20
  29. data/lib/action_controller/helpers.rb +2 -5
  30. data/lib/action_controller/integration.rb +40 -16
  31. data/lib/action_controller/layout.rb +11 -8
  32. data/lib/action_controller/macros/auto_complete.rb +3 -2
  33. data/lib/action_controller/macros/in_place_editing.rb +3 -2
  34. data/lib/action_controller/mime_responds.rb +41 -29
  35. data/lib/action_controller/mime_type.rb +68 -10
  36. data/lib/action_controller/pagination.rb +4 -3
  37. data/lib/action_controller/request.rb +22 -14
  38. data/lib/action_controller/rescue.rb +25 -22
  39. data/lib/action_controller/resources.rb +302 -0
  40. data/lib/action_controller/response.rb +20 -2
  41. data/lib/action_controller/response.rb.rej +17 -0
  42. data/lib/action_controller/routing.rb +1165 -567
  43. data/lib/action_controller/scaffolding.rb +30 -31
  44. data/lib/action_controller/session/active_record_store.rb +2 -0
  45. data/lib/action_controller/session/drb_store.rb +4 -0
  46. data/lib/action_controller/session/mem_cache_store.rb +4 -0
  47. data/lib/action_controller/session_management.rb +6 -9
  48. data/lib/action_controller/status_codes.rb +89 -0
  49. data/lib/action_controller/streaming.rb +6 -15
  50. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +5 -5
  51. data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -2
  52. data/lib/action_controller/templates/rescues/routing_error.rhtml +4 -4
  53. data/lib/action_controller/templates/rescues/template_error.rhtml +1 -1
  54. data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
  55. data/lib/action_controller/test_process.rb +52 -30
  56. data/lib/action_controller/url_rewriter.rb +63 -29
  57. data/lib/action_controller/vendor/html-scanner/html/document.rb +1 -0
  58. data/lib/action_controller/vendor/html-scanner/html/node.rb +3 -4
  59. data/lib/action_controller/vendor/html-scanner/html/selector.rb +822 -0
  60. data/lib/action_controller/verification.rb +22 -11
  61. data/lib/action_pack.rb +1 -1
  62. data/lib/action_pack/version.rb +2 -2
  63. data/lib/action_view.rb +1 -1
  64. data/lib/action_view/base.rb +46 -43
  65. data/lib/action_view/compiled_templates.rb +1 -1
  66. data/lib/action_view/helpers/active_record_helper.rb +54 -17
  67. data/lib/action_view/helpers/asset_tag_helper.rb +97 -46
  68. data/lib/action_view/helpers/capture_helper.rb +1 -1
  69. data/lib/action_view/helpers/date_helper.rb +258 -136
  70. data/lib/action_view/helpers/debug_helper.rb +1 -1
  71. data/lib/action_view/helpers/deprecated_helper.rb +34 -0
  72. data/lib/action_view/helpers/form_helper.rb +75 -35
  73. data/lib/action_view/helpers/form_options_helper.rb +7 -5
  74. data/lib/action_view/helpers/form_tag_helper.rb +44 -6
  75. data/lib/action_view/helpers/java_script_macros_helper.rb +59 -46
  76. data/lib/action_view/helpers/javascript_helper.rb +71 -10
  77. data/lib/action_view/helpers/javascripts/controls.js +41 -23
  78. data/lib/action_view/helpers/javascripts/dragdrop.js +105 -76
  79. data/lib/action_view/helpers/javascripts/effects.js +293 -163
  80. data/lib/action_view/helpers/javascripts/prototype.js +897 -389
  81. data/lib/action_view/helpers/javascripts/prototype.js.rej +561 -0
  82. data/lib/action_view/helpers/number_helper.rb +111 -65
  83. data/lib/action_view/helpers/prototype_helper.rb +84 -109
  84. data/lib/action_view/helpers/scriptaculous_helper.rb +5 -0
  85. data/lib/action_view/helpers/tag_helper.rb +69 -16
  86. data/lib/action_view/helpers/text_helper.rb +149 -112
  87. data/lib/action_view/helpers/url_helper.rb +200 -107
  88. data/lib/action_view/template_error.rb +66 -42
  89. data/test/abstract_unit.rb +4 -2
  90. data/test/active_record_unit.rb +84 -56
  91. data/test/activerecord/active_record_assertions_test.rb +26 -18
  92. data/test/activerecord/active_record_store_test.rb +4 -36
  93. data/test/activerecord/pagination_test.rb +1 -6
  94. data/test/controller/action_pack_assertions_test.rb +230 -113
  95. data/test/controller/addresses_render_test.rb +2 -6
  96. data/test/controller/assert_select_test.rb +576 -0
  97. data/test/controller/base_test.rb +73 -3
  98. data/test/controller/caching_test.rb +228 -0
  99. data/test/controller/capture_test.rb +12 -10
  100. data/test/controller/cgi_test.rb +89 -12
  101. data/test/controller/components_test.rb +24 -2
  102. data/test/controller/content_type_test.rb +139 -0
  103. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  104. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  105. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  106. data/test/controller/cookie_test.rb +33 -25
  107. data/test/controller/deprecated_instance_variables_test.rb +48 -0
  108. data/test/controller/deprecation/deprecated_base_methods_test.rb +60 -0
  109. data/test/controller/fake_controllers.rb +0 -1
  110. data/test/controller/filters_test.rb +301 -16
  111. data/test/controller/flash_test.rb +19 -2
  112. data/test/controller/helper_test.rb +2 -2
  113. data/test/controller/integration_test.rb +154 -0
  114. data/test/controller/layout_test.rb +115 -1
  115. data/test/controller/mime_responds_test.rb +94 -0
  116. data/test/controller/mime_type_test.rb +9 -0
  117. data/test/controller/new_render_test.rb +161 -11
  118. data/test/controller/raw_post_test.rb +52 -15
  119. data/test/controller/redirect_test.rb +27 -14
  120. data/test/controller/render_test.rb +76 -29
  121. data/test/controller/request_test.rb +55 -4
  122. data/test/controller/resources_test.rb +274 -0
  123. data/test/controller/routing_test.rb +1533 -824
  124. data/test/controller/selector_test.rb +628 -0
  125. data/test/controller/send_file_test.rb +9 -1
  126. data/test/controller/session_management_test.rb +51 -0
  127. data/test/controller/test_test.rb +113 -29
  128. data/test/controller/url_rewriter_test.rb +86 -17
  129. data/test/controller/verification_test.rb +19 -17
  130. data/test/controller/webservice_test.rb +0 -7
  131. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
  132. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
  133. data/test/fixtures/content_type/render_default_for_rjs.rjs +1 -0
  134. data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
  135. data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +1 -0
  136. data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +1 -0
  137. data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +1 -0
  138. data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +1 -0
  139. data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +1 -0
  140. data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +1 -0
  141. data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +1 -0
  142. data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +1 -0
  143. data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +1 -0
  144. data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +1 -0
  145. data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +1 -0
  146. data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +1 -0
  147. data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +1 -0
  148. data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +1 -0
  149. data/test/fixtures/multipart/binary_file +0 -0
  150. data/test/fixtures/public/javascripts/application.js +1 -0
  151. data/test/fixtures/test/_hello.rxml +1 -0
  152. data/test/fixtures/test/hello_world_container.rxml +3 -0
  153. data/test/fixtures/topic.rb +2 -2
  154. data/test/template/active_record_helper_test.rb +83 -12
  155. data/test/template/asset_tag_helper_test.rb +75 -95
  156. data/test/template/compiled_templates_test.rb +1 -0
  157. data/test/template/date_helper_test.rb +873 -181
  158. data/test/template/deprecated_helper_test.rb +36 -0
  159. data/test/template/deprecated_instance_variables_test.rb +43 -0
  160. data/test/template/form_helper_test.rb +77 -1
  161. data/test/template/form_options_helper_test.rb +4 -0
  162. data/test/template/form_tag_helper_test.rb +66 -2
  163. data/test/template/java_script_macros_helper_test.rb +4 -1
  164. data/test/template/javascript_helper_test.rb +29 -0
  165. data/test/template/number_helper_test.rb +63 -27
  166. data/test/template/prototype_helper_test.rb +77 -34
  167. data/test/template/tag_helper_test.rb +34 -6
  168. data/test/template/text_helper_test.rb +69 -34
  169. data/test/template/url_helper_test.rb +168 -16
  170. data/test/testing_sandbox.rb +7 -22
  171. metadata +66 -20
  172. data/filler.txt +0 -50
  173. data/lib/action_controller/code_generation.rb +0 -235
  174. data/lib/action_controller/vendor/xml_simple.rb +0 -1019
  175. data/test/controller/caching_filestore.rb +0 -74
  176. data/test/fixtures/application_root/app/controllers/a_class_that_contains_a_controller/poorly_placed_controller.rb +0 -7
  177. data/test/fixtures/application_root/app/controllers/module_that_holds_controllers/nested_controller.rb +0 -3
  178. data/test/fixtures/application_root/app/models/a_class_that_contains_a_controller.rb +0 -7
  179. data/test/fixtures/dont_load.rb +0 -3
@@ -12,6 +12,7 @@ module Submodule
12
12
 
13
13
  hide_action :hidden_action
14
14
  def hidden_action
15
+ raise "Noooo!"
15
16
  end
16
17
 
17
18
  def another_hidden_action
@@ -23,7 +24,6 @@ module Submodule
23
24
  end
24
25
  end
25
26
  class EmptyController < ActionController::Base
26
- include ActionController::Caching
27
27
  end
28
28
  class NonEmptyController < ActionController::Base
29
29
  def public_action
@@ -34,10 +34,27 @@ class NonEmptyController < ActionController::Base
34
34
  end
35
35
  end
36
36
 
37
+ class MethodMissingController < ActionController::Base
38
+
39
+ hide_action :shouldnt_be_called
40
+ def shouldnt_be_called
41
+ raise "NO WAY!"
42
+ end
43
+
44
+ protected
45
+
46
+ def method_missing(selector)
47
+ render :text => selector.to_s
48
+ end
49
+
50
+ end
51
+
37
52
  class ControllerClassTests < Test::Unit::TestCase
38
53
  def test_controller_path
39
54
  assert_equal 'empty', EmptyController.controller_path
55
+ assert_equal EmptyController.controller_path, EmptyController.new.controller_path
40
56
  assert_equal 'submodule/contained_empty', Submodule::ContainedEmptyController.controller_path
57
+ assert_equal Submodule::ContainedEmptyController.controller_path, Submodule::ContainedEmptyController.new.controller_path
41
58
  end
42
59
  def test_controller_name
43
60
  assert_equal 'empty', EmptyController.controller_name
@@ -57,10 +74,63 @@ class ControllerInstanceTests < Test::Unit::TestCase
57
74
 
58
75
  def test_action_methods
59
76
  @empty_controllers.each do |c|
60
- assert_equal Set.new, c.send(:action_methods), "#{c.class.controller_path} should be empty!"
77
+ hide_mocha_methods_from_controller(c)
78
+ assert_equal Set.new, c.send(:action_methods), "#{c.controller_path} should be empty!"
61
79
  end
62
80
  @non_empty_controllers.each do |c|
63
- assert_equal Set.new('public_action'), c.send(:action_methods), "#{c.class.controller_path} should not be empty!"
81
+ hide_mocha_methods_from_controller(c)
82
+ assert_equal Set.new('public_action'), c.send(:action_methods), "#{c.controller_path} should not be empty!"
64
83
  end
65
84
  end
85
+
86
+ protected
87
+
88
+ # Mocha adds methods to Object which are then included in the public_instance_methods
89
+ # This method hides those from the controller so the above tests won't know the difference
90
+ def hide_mocha_methods_from_controller(controller)
91
+ mocha_methods = [:expects, :metaclass, :mocha, :mocha_inspect, :reset_mocha, :stubba_object, :stubba_method, :stubs, :verify]
92
+ controller.class.send(:hide_action, *mocha_methods)
93
+ end
94
+
66
95
  end
96
+
97
+
98
+ class PerformActionTest < Test::Unit::TestCase
99
+ def use_controller(controller_class)
100
+ @controller = controller_class.new
101
+
102
+ # enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
103
+ # a more accurate simulation of what happens in "real life".
104
+ @controller.logger = Logger.new(nil)
105
+
106
+ @request = ActionController::TestRequest.new
107
+ @response = ActionController::TestResponse.new
108
+
109
+ @request.host = "www.nextangle.com"
110
+ end
111
+
112
+ def test_get_on_priv_should_show_selector
113
+ use_controller MethodMissingController
114
+ get :shouldnt_be_called
115
+ assert_response :success
116
+ assert_equal 'shouldnt_be_called', @response.body
117
+ end
118
+
119
+ def test_method_missing_is_not_an_action_name
120
+ use_controller MethodMissingController
121
+ assert ! @controller.send(:action_methods).include?('method_missing')
122
+
123
+ get :method_missing
124
+ assert_response :success
125
+ assert_equal 'method_missing', @response.body
126
+ end
127
+
128
+ def test_get_on_hidden_should_fail
129
+ use_controller NonEmptyController
130
+ get :hidden_action
131
+ assert_response 404
132
+
133
+ get :another_hidden_action
134
+ assert_response 404
135
+ end
136
+ end
@@ -0,0 +1,228 @@
1
+ require 'fileutils'
2
+ require File.dirname(__FILE__) + '/../abstract_unit'
3
+
4
+ CACHE_DIR = 'test_cache'
5
+ # Don't change '/../temp/' cavalierly or you might hoze something you don't want hozed
6
+ FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
7
+ ActionController::Base.perform_caching = true
8
+ ActionController::Base.page_cache_directory = FILE_STORE_PATH
9
+ ActionController::Base.fragment_cache_store = :file_store, FILE_STORE_PATH
10
+
11
+ class PageCachingTestController < ActionController::Base
12
+ caches_page :ok, :no_content, :found, :not_found
13
+
14
+ def ok
15
+ head :ok
16
+ end
17
+
18
+ def no_content
19
+ head :no_content
20
+ end
21
+
22
+ def found
23
+ redirect_to :action => 'ok'
24
+ end
25
+
26
+ def not_found
27
+ head :not_found
28
+ end
29
+ end
30
+
31
+ class PageCachingTest < Test::Unit::TestCase
32
+ def setup
33
+ ActionController::Routing::Routes.draw do |map|
34
+ map.main '', :controller => 'posts'
35
+ map.resources :posts
36
+ map.connect ':controller/:action/:id'
37
+ end
38
+
39
+ @request = ActionController::TestRequest.new
40
+ @request.host = 'hostname.com'
41
+
42
+ @response = ActionController::TestResponse.new
43
+ @controller = PageCachingTestController.new
44
+
45
+ @params = {:controller => 'posts', :action => 'index', :only_path => true, :skip_relative_url_root => true}
46
+ @rewriter = ActionController::UrlRewriter.new(@request, @params)
47
+
48
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
49
+ FileUtils.mkdir_p(FILE_STORE_PATH)
50
+ end
51
+
52
+ def teardown
53
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
54
+ end
55
+
56
+ def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
57
+ @params[:format] = 'rss'
58
+ assert_equal '/posts.rss', @rewriter.rewrite(@params)
59
+ @params[:format] = nil
60
+ assert_equal '/', @rewriter.rewrite(@params)
61
+ end
62
+
63
+ def test_should_cache_get_with_ok_status
64
+ get :ok
65
+ assert_response :ok
66
+ assert_page_cached :ok, "get with ok status should have been cached"
67
+ end
68
+
69
+ [:ok, :no_content, :found, :not_found].each do |status|
70
+ [:get, :post, :put, :delete].each do |method|
71
+ unless method == :get and status == :ok
72
+ define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
73
+ @request.env['REQUEST_METHOD'] = method.to_s.upcase
74
+ process status
75
+ assert_response status
76
+ assert_page_not_cached status, "#{method} with #{status} status shouldn't have been cached"
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ private
83
+ def assert_page_cached(action, message = "#{action} should have been cached")
84
+ assert page_cached?(action), message
85
+ end
86
+
87
+ def assert_page_not_cached(action, message = "#{action} shouldn't have been cached")
88
+ assert !page_cached?(action), message
89
+ end
90
+
91
+ def page_cached?(action)
92
+ File.exist? "#{FILE_STORE_PATH}/page_caching_test/#{action}.html"
93
+ end
94
+ end
95
+
96
+ class ActionCachingTestController < ActionController::Base
97
+ caches_action :index
98
+
99
+ def index
100
+ @cache_this = Time.now.to_f.to_s
101
+ render :text => @cache_this
102
+ end
103
+
104
+ def expire
105
+ expire_action :controller => 'action_caching_test', :action => 'index'
106
+ render :nothing => true
107
+ end
108
+
109
+ end
110
+
111
+ class ActionCachingMockController
112
+ attr_accessor :mock_url_for
113
+ attr_accessor :mock_path
114
+
115
+ def initialize
116
+ yield self if block_given?
117
+ end
118
+
119
+ def url_for(*args)
120
+ @mock_url_for
121
+ end
122
+
123
+ def request
124
+ mocked_path = @mock_path
125
+ Object.new.instance_eval(<<-EVAL)
126
+ def path; '#{@mock_path}' end
127
+ self
128
+ EVAL
129
+ end
130
+ end
131
+
132
+ class ActionCacheTest < Test::Unit::TestCase
133
+ def setup
134
+ reset!
135
+ FileUtils.mkdir_p(FILE_STORE_PATH)
136
+ @path_class = ActionController::Caching::Actions::ActionCachePath
137
+ @mock_controller = ActionCachingMockController.new
138
+ end
139
+
140
+ def teardown
141
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
142
+ end
143
+
144
+ def test_simple_action_cache
145
+ get :index
146
+ cached_time = content_to_cache
147
+ assert_equal cached_time, @response.body
148
+ reset!
149
+
150
+ get :index
151
+ assert_equal cached_time, @response.body
152
+ end
153
+
154
+ def test_cache_expiration
155
+ get :index
156
+ cached_time = content_to_cache
157
+ reset!
158
+
159
+ get :index
160
+ assert_equal cached_time, @response.body
161
+ reset!
162
+
163
+ get :expire
164
+ reset!
165
+
166
+ get :index
167
+ new_cached_time = content_to_cache
168
+ assert_not_equal cached_time, @response.body
169
+ reset!
170
+
171
+ get :index
172
+ assert_response :success
173
+ assert_equal new_cached_time, @response.body
174
+ end
175
+
176
+ def test_cache_is_scoped_by_subdomain
177
+ @request.host = 'jamis.hostname.com'
178
+ get :index
179
+ jamis_cache = content_to_cache
180
+
181
+ @request.host = 'david.hostname.com'
182
+ get :index
183
+ david_cache = content_to_cache
184
+ assert_not_equal jamis_cache, @response.body
185
+
186
+ @request.host = 'jamis.hostname.com'
187
+ get :index
188
+ assert_equal jamis_cache, @response.body
189
+
190
+ @request.host = 'david.hostname.com'
191
+ get :index
192
+ assert_equal david_cache, @response.body
193
+ end
194
+
195
+ def test_xml_version_of_resource_is_treated_as_different_cache
196
+ @mock_controller.mock_url_for = 'http://example.org/posts/'
197
+ @mock_controller.mock_path = '/posts/index.xml'
198
+ path_object = @path_class.new(@mock_controller)
199
+ assert_equal 'xml', path_object.extension
200
+ assert_equal 'example.org/posts/index.xml', path_object.path
201
+ end
202
+
203
+ def test_empty_path_is_normalized
204
+ @mock_controller.mock_url_for = 'http://example.org/'
205
+ @mock_controller.mock_path = '/'
206
+
207
+ assert_equal 'example.org/index', @path_class.path_for(@mock_controller)
208
+ end
209
+
210
+ def test_file_extensions
211
+ get :index, :id => 'kitten.jpg'
212
+ get :index, :id => 'kitten.jpg'
213
+
214
+ assert_response :success
215
+ end
216
+
217
+ private
218
+ def content_to_cache
219
+ assigns(:cache_this)
220
+ end
221
+
222
+ def reset!
223
+ @request = ActionController::TestRequest.new
224
+ @response = ActionController::TestResponse.new
225
+ @controller = ActionCachingTestController.new
226
+ @request.host = 'hostname.com'
227
+ end
228
+ end
@@ -7,15 +7,15 @@ class CaptureController < ActionController::Base
7
7
  def content_for
8
8
  render :layout => "talk_from_action"
9
9
  end
10
-
10
+
11
11
  def erb_content_for
12
12
  render :layout => "talk_from_action"
13
13
  end
14
-
14
+
15
15
  def block_content_for
16
16
  render :layout => "talk_from_action"
17
17
  end
18
-
18
+
19
19
  def non_erb_block_content_for
20
20
  render :layout => "talk_from_action"
21
21
  end
@@ -43,36 +43,38 @@ class CaptureTest < Test::Unit::TestCase
43
43
  get :capturing
44
44
  assert_equal "Dreamy days", @response.body.strip
45
45
  end
46
-
46
+
47
47
  def test_content_for
48
48
  get :content_for
49
49
  assert_equal expected_content_for_output, @response.body
50
50
  end
51
-
51
+
52
52
  def test_erb_content_for
53
53
  get :content_for
54
54
  assert_equal expected_content_for_output, @response.body
55
55
  end
56
-
56
+
57
57
  def test_block_content_for
58
58
  get :block_content_for
59
59
  assert_equal expected_content_for_output, @response.body
60
60
  end
61
-
61
+
62
62
  def test_non_erb_block_content_for
63
63
  get :non_erb_block_content_for
64
64
  assert_equal expected_content_for_output, @response.body
65
65
  end
66
66
 
67
67
  def test_update_element_with_capture
68
- get :update_element_with_capture
68
+ assert_deprecated 'update_element_function' do
69
+ get :update_element_with_capture
70
+ end
69
71
  assert_equal(
70
72
  "<script type=\"text/javascript\">\n//<![CDATA[\n$('products').innerHTML = '\\n <p>Product 1</p>\\n <p>Product 2</p>\\n';\n\n//]]>\n</script>" +
71
- "\n\n$('status').innerHTML = '\\n <b>You bought something!</b>\\n';",
73
+ "\n\n$('status').innerHTML = '\\n <b>You bought something!</b>\\n';",
72
74
  @response.body.strip
73
75
  )
74
76
  end
75
-
77
+
76
78
  private
77
79
  def expected_content_for_output
78
80
  "<title>Putting stuff in the title!</title>\n\nGreat stuff!"
@@ -17,6 +17,7 @@ class CGITest < Test::Unit::TestCase
17
17
  @query_string_without_equal = "action"
18
18
  @query_string_with_many_ampersands =
19
19
  "&action=create_customer&&&full_name=David%20Heinemeier%20Hansson"
20
+ @query_string_with_empty_key = "action=create_customer&full_name=David%20Heinemeier%20Hansson&=Save"
20
21
  end
21
22
 
22
23
  def test_query_string
@@ -27,13 +28,43 @@ class CGITest < Test::Unit::TestCase
27
28
  end
28
29
 
29
30
  def test_deep_query_string
30
- assert_equal({'x' => {'y' => {'z' => '10'}}}, CGIMethods.parse_query_parameters('x[y][z]=10'))
31
+ expected = {'x' => {'y' => {'z' => '10'}}}
32
+ assert_equal(expected, CGIMethods.parse_query_parameters('x[y][z]=10'))
31
33
  end
32
34
 
33
35
  def test_deep_query_string_with_array
34
36
  assert_equal({'x' => {'y' => {'z' => ['10']}}}, CGIMethods.parse_query_parameters('x[y][z][]=10'))
35
37
  assert_equal({'x' => {'y' => {'z' => ['10', '5']}}}, CGIMethods.parse_query_parameters('x[y][z][]=10&x[y][z][]=5'))
36
38
  end
39
+
40
+ def test_deep_query_string_with_array_of_hash
41
+ assert_equal({'x' => {'y' => [{'z' => '10'}]}}, CGIMethods.parse_query_parameters('x[y][][z]=10'))
42
+ assert_equal({'x' => {'y' => [{'z' => '10', 'w' => '10'}]}}, CGIMethods.parse_query_parameters('x[y][][z]=10&x[y][][w]=10'))
43
+ end
44
+
45
+ def test_deep_query_string_with_array_of_hashes_with_one_pair
46
+ assert_equal({'x' => {'y' => [{'z' => '10'}, {'z' => '20'}]}}, CGIMethods.parse_query_parameters('x[y][][z]=10&x[y][][z]=20'))
47
+ assert_equal("10", CGIMethods.parse_query_parameters('x[y][][z]=10&x[y][][z]=20')["x"]["y"].first["z"])
48
+ assert_equal("10", CGIMethods.parse_query_parameters('x[y][][z]=10&x[y][][z]=20').with_indifferent_access[:x][:y].first[:z])
49
+ end
50
+
51
+ def test_request_hash_parsing
52
+ query = {
53
+ "note[viewers][viewer][][type]" => ["User", "Group"],
54
+ "note[viewers][viewer][][id]" => ["1", "2"]
55
+ }
56
+
57
+ expected = { "note" => { "viewers"=>{"viewer"=>[{ "id"=>"1", "type"=>"User"}, {"type"=>"Group", "id"=>"2"} ]} } }
58
+
59
+ assert_equal(expected, CGIMethods.parse_request_parameters(query))
60
+ end
61
+
62
+ def test_deep_query_string_with_array_of_hashes_with_multiple_pairs
63
+ assert_equal(
64
+ {'x' => {'y' => [{'z' => '10', 'w' => 'a'}, {'z' => '20', 'w' => 'b'}]}},
65
+ CGIMethods.parse_query_parameters('x[y][][z]=10&x[y][][w]=a&x[y][][z]=20&x[y][][w]=b')
66
+ )
67
+ end
37
68
 
38
69
  def test_query_string_with_nil
39
70
  assert_equal(
@@ -69,6 +100,13 @@ class CGITest < Test::Unit::TestCase
69
100
  CGIMethods.parse_query_parameters(@query_string_without_equal)
70
101
  )
71
102
  end
103
+
104
+ def test_query_string_with_empty_key
105
+ assert_equal(
106
+ { "action" => "create_customer", "full_name" => "David Heinemeier Hansson" },
107
+ CGIMethods.parse_query_parameters(@query_string_with_empty_key)
108
+ )
109
+ end
72
110
 
73
111
  def test_query_string_with_many_ampersands
74
112
  assert_equal(
@@ -87,7 +125,8 @@ class CGITest < Test::Unit::TestCase
87
125
  "something_nil" => [ nil ],
88
126
  "something_empty" => [ "" ],
89
127
  "products[first]" => [ "Apple Computer" ],
90
- "products[second]" => [ "Pc" ]
128
+ "products[second]" => [ "Pc" ],
129
+ "" => [ 'Save' ]
91
130
  }
92
131
 
93
132
  expected_output = {
@@ -116,9 +155,10 @@ class CGITest < Test::Unit::TestCase
116
155
  end
117
156
 
118
157
  def test_parse_params_from_multipart_upload
119
- mockup = Struct.new(:content_type, :original_filename)
158
+ mockup = Struct.new(:content_type, :original_filename, :read, :rewind)
120
159
  file = mockup.new('img/jpeg', 'foo.jpg')
121
160
  ie_file = mockup.new('img/jpeg', 'c:\\Documents and Settings\\foo\\Desktop\\bar.jpg')
161
+ non_file_text_part = mockup.new('text/plain', '', 'abc')
122
162
 
123
163
  input = {
124
164
  "something" => [ StringIO.new("") ],
@@ -129,9 +169,10 @@ class CGITest < Test::Unit::TestCase
129
169
  "products[string]" => [ StringIO.new("Apple Computer") ],
130
170
  "products[file]" => [ file ],
131
171
  "ie_products[string]" => [ StringIO.new("Microsoft") ],
132
- "ie_products[file]" => [ ie_file ]
172
+ "ie_products[file]" => [ ie_file ],
173
+ "text_part" => [non_file_text_part]
133
174
  }
134
-
175
+
135
176
  expected_output = {
136
177
  "something" => "",
137
178
  "array_of_stringios" => ["One", "Two"],
@@ -153,7 +194,8 @@ class CGITest < Test::Unit::TestCase
153
194
  "ie_products" => {
154
195
  "string" => "Microsoft",
155
196
  "file" => ie_file
156
- }
197
+ },
198
+ "text_part" => "abc"
157
199
  }
158
200
 
159
201
  params = CGIMethods.parse_request_parameters(input)
@@ -206,29 +248,36 @@ class CGITest < Test::Unit::TestCase
206
248
 
207
249
  def test_parse_params_with_single_brackets_in_middle
208
250
  input = { "a/b[c]d" => %w(e) }
209
- expected = { "a/b[c]d" => "e" }
251
+ expected = { "a/b" => {} }
210
252
  assert_equal expected, CGIMethods.parse_request_parameters(input)
211
253
  end
212
254
 
213
255
  def test_parse_params_with_separated_brackets
214
256
  input = { "a/b@[c]d[e]" => %w(f) }
215
- expected = { "a/b@" => { "c]d[e" => "f" }}
257
+ expected = { "a/b@" => { }}
216
258
  assert_equal expected, CGIMethods.parse_request_parameters(input)
217
259
  end
218
260
 
219
261
  def test_parse_params_with_separated_brackets_and_array
220
262
  input = { "a/b@[c]d[e][]" => %w(f) }
221
- expected = { "a/b@" => { "c]d[e" => ["f"] }}
263
+ expected = { "a/b@" => { }}
222
264
  assert_equal expected , CGIMethods.parse_request_parameters(input)
223
265
  end
224
266
 
225
267
  def test_parse_params_with_unmatched_brackets_and_array
226
268
  input = { "a/b@[c][d[e][]" => %w(f) }
227
- expected = { "a/b@" => { "c" => { "d[e" => ["f"] }}}
269
+ expected = { "a/b@" => { "c" => { }}}
270
+ assert_equal expected, CGIMethods.parse_request_parameters(input)
271
+ end
272
+
273
+ def test_parse_params_with_nil_key
274
+ input = { nil => nil, "test2" => %w(value1) }
275
+ expected = { "test2" => "value1" }
228
276
  assert_equal expected, CGIMethods.parse_request_parameters(input)
229
277
  end
230
278
  end
231
279
 
280
+
232
281
  class MultipartCGITest < Test::Unit::TestCase
233
282
  FIXTURE_PATH = File.dirname(__FILE__) + '/../fixtures/multipart'
234
283
 
@@ -292,23 +341,39 @@ class MultipartCGITest < Test::Unit::TestCase
292
341
  assert_equal 'bar', params['foo']
293
342
 
294
343
  # Ruby CGI doesn't handle multipart/mixed for us.
295
- assert_kind_of StringIO, params['files']
344
+ assert_kind_of String, params['files']
296
345
  assert_equal 19756, params['files'].size
297
346
  end
298
347
 
348
+ # Rewind readable cgi params so others may reread them (such as CGI::Session
349
+ # when passing the session id in a multipart form).
350
+ def test_multipart_param_rewound
351
+ params = process('text_file')
352
+ assert_equal 'bar', @cgi.params['foo'][0].read
353
+ end
354
+
299
355
  private
300
356
  def process(name)
301
357
  old_stdin = $stdin
302
358
  File.open(File.join(FIXTURE_PATH, name), 'rb') do |file|
303
359
  ENV['CONTENT_LENGTH'] = file.stat.size.to_s
304
360
  $stdin = file
305
- CGIMethods.parse_request_parameters CGI.new.params
361
+ @cgi = CGI.new
362
+ CGIMethods.parse_request_parameters @cgi.params
306
363
  end
307
364
  ensure
308
365
  $stdin = old_stdin
309
366
  end
310
367
  end
311
368
 
369
+ # Ensures that PUT works with multipart as well as POST.
370
+ class PutMultipartCGITest < MultipartCGITest
371
+ def setup
372
+ super
373
+ ENV['REQUEST_METHOD'] = 'PUT'
374
+ end
375
+ end
376
+
312
377
 
313
378
  class CGIRequestTest < Test::Unit::TestCase
314
379
  def setup
@@ -360,4 +425,16 @@ class CGIRequestTest < Test::Unit::TestCase
360
425
  assert_equal ["c84ace84796670c052c6ceb2451fb0f2"], alt_cookies["_session_id"]
361
426
  assert_equal ["yes"], alt_cookies["is_admin"]
362
427
  end
428
+
429
+ def test_unbalanced_query_string_with_array
430
+ assert_equal(
431
+ {'location' => ["1", "2"], 'age_group' => ["2"]},
432
+ CGIMethods.parse_query_parameters("location[]=1&location[]=2&age_group[]=2")
433
+ )
434
+ assert_equal(
435
+ {'location' => ["1", "2"], 'age_group' => ["2"]},
436
+ CGIMethods.parse_request_parameters({'location[]' => ["1", "2"],
437
+ 'age_group[]' => ["2"]})
438
+ )
439
+ end
363
440
  end