aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/test
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/test')
-rw-r--r--actionpack/test/abstract/translation_test.rb1
-rw-r--r--actionpack/test/abstract_unit.rb40
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb2
-rw-r--r--actionpack/test/controller/api/data_streaming_test.rb2
-rw-r--r--actionpack/test/controller/api/with_helpers_test.rb42
-rw-r--r--actionpack/test/controller/base_test.rb27
-rw-r--r--actionpack/test/controller/caching_test.rb71
-rw-r--r--actionpack/test/controller/filters_test.rb2
-rw-r--r--actionpack/test/controller/helper_test.rb8
-rw-r--r--actionpack/test/controller/integration_test.rb16
-rw-r--r--actionpack/test/controller/live_stream_test.rb3
-rw-r--r--actionpack/test/controller/metal_test.rb30
-rw-r--r--actionpack/test/controller/mime/accept_format_test.rb2
-rw-r--r--actionpack/test/controller/mime/respond_to_test.rb2
-rw-r--r--actionpack/test/controller/new_base/render_file_test.rb10
-rw-r--r--actionpack/test/controller/new_base/render_implicit_action_test.rb2
-rw-r--r--actionpack/test/controller/parameters/accessors_test.rb68
-rw-r--r--actionpack/test/controller/parameters/mutators_test.rb21
-rw-r--r--actionpack/test/controller/parameters/nested_parameters_permit_test.rb5
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb130
-rw-r--r--actionpack/test/controller/params_wrapper_test.rb31
-rw-r--r--actionpack/test/controller/redirect_test.rb8
-rw-r--r--actionpack/test/controller/render_test.rb13
-rw-r--r--actionpack/test/controller/renderer_test.rb24
-rw-r--r--actionpack/test/controller/request/test_request_test.rb20
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb131
-rw-r--r--actionpack/test/controller/required_params_test.rb24
-rw-r--r--actionpack/test/controller/routing_test.rb4
-rw-r--r--actionpack/test/controller/send_file_test.rb2
-rw-r--r--actionpack/test/controller/test_case_test.rb18
-rw-r--r--actionpack/test/controller/url_for_test.rb2
-rw-r--r--actionpack/test/dispatch/callbacks_test.rb18
-rw-r--r--actionpack/test/dispatch/cookies_test.rb206
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb4
-rw-r--r--actionpack/test/dispatch/prefix_generation_test.rb90
-rw-r--r--actionpack/test/dispatch/reloader_test.rb128
-rw-r--r--actionpack/test/dispatch/request/multipart_params_parsing_test.rb2
-rw-r--r--actionpack/test/dispatch/request/session_test.rb18
-rw-r--r--actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request_test.rb25
-rw-r--r--actionpack/test/dispatch/routing/custom_url_helpers_test.rb331
-rw-r--r--actionpack/test/dispatch/routing/route_set_test.rb9
-rw-r--r--actionpack/test/dispatch/routing_test.rb142
-rw-r--r--actionpack/test/dispatch/runner_test.rb1
-rw-r--r--actionpack/test/dispatch/ssl_test.rb6
-rw-r--r--actionpack/test/dispatch/static_test.rb10
-rw-r--r--actionpack/test/dispatch/system_testing/driver_test.rb35
-rw-r--r--actionpack/test/dispatch/system_testing/screenshot_helper_test.rb41
-rw-r--r--actionpack/test/dispatch/system_testing/server_test.rb17
-rw-r--r--actionpack/test/dispatch/system_testing/system_test_case_test.rb65
-rw-r--r--actionpack/test/dispatch/uploaded_file_test.rb6
-rw-r--r--actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb2
-rw-r--r--actionpack/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder2
-rw-r--r--actionpack/test/fixtures/functional_caching/formatted_fragment_cached_with_variant.html+phone.erb2
-rw-r--r--actionpack/test/fixtures/functional_caching/fragment_cached.html.erb2
-rw-r--r--actionpack/test/fixtures/layouts/builder.builder2
-rw-r--r--actionpack/test/fixtures/old_content_type/render_default_for_builder.builder2
-rw-r--r--actionpack/test/fixtures/respond_to/using_defaults.xml.builder2
-rw-r--r--actionpack/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder2
-rw-r--r--actionpack/test/fixtures/test/formatted_xml_erb.builder2
-rw-r--r--actionpack/test/fixtures/test/hello_xml_world.builder2
-rw-r--r--actionpack/test/journey/gtg/transition_table_test.rb34
-rw-r--r--actionpack/test/journey/path/pattern_test.rb6
-rw-r--r--actionpack/test/journey/router/utils_test.rb13
-rw-r--r--actionpack/test/lib/controller/fake_models.rb8
65 files changed, 1598 insertions, 402 deletions
diff --git a/actionpack/test/abstract/translation_test.rb b/actionpack/test/abstract/translation_test.rb
index 0c4071df8d..4893144905 100644
--- a/actionpack/test/abstract/translation_test.rb
+++ b/actionpack/test/abstract/translation_test.rb
@@ -62,6 +62,7 @@ module AbstractController
def test_default_translation
@controller.stub :action_name, :index do
assert_equal "bar", @controller.t("one.two")
+ assert_equal "baz", @controller.t(".twoz", default: ["baz", :twoz])
end
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 7c113426a5..caa56018f8 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -1,6 +1,8 @@
-$:.unshift(File.dirname(__FILE__) + "/lib")
-$:.unshift(File.dirname(__FILE__) + "/fixtures/helpers")
-$:.unshift(File.dirname(__FILE__) + "/fixtures/alternate_helpers")
+# frozen_string_literal: true
+
+$:.unshift File.expand_path("lib", __dir__)
+$:.unshift File.expand_path("fixtures/helpers", __dir__)
+$:.unshift File.expand_path("fixtures/alternate_helpers", __dir__)
require "active_support/core_ext/kernel/reporting"
@@ -56,7 +58,7 @@ ActiveSupport::Deprecation.debug = true
# Disable available locale checks to avoid warnings running the test suite.
I18n.enforce_available_locales = false
-FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), "fixtures")
+FIXTURE_LOAD_PATH = File.join(__dir__, "fixtures")
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
@@ -156,7 +158,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
end
def with_autoload_path(path)
- path = File.join(File.dirname(__FILE__), "fixtures", path)
+ path = File.join(__dir__, "fixtures", path)
if ActiveSupport::Dependencies.autoload_paths.include?(path)
yield
else
@@ -175,7 +177,7 @@ end
class Rack::TestCase < ActionDispatch::IntegrationTest
def self.testing(klass = nil)
if klass
- @testing = "/#{klass.name.underscore}".sub!(/_controller$/, "")
+ @testing = "/#{klass.name.underscore}".sub(/_controller$/, "")
else
@testing
end
@@ -354,15 +356,6 @@ class CommentsController < ResourcesController; end
class AccountsController < ResourcesController; end
class ImagesController < ResourcesController; end
-# Skips the current run on Rubinius using Minitest::Assertions#skip
-def rubinius_skip(message = "")
- skip message if RUBY_ENGINE == "rbx"
-end
-# Skips the current run on JRuby using Minitest::Assertions#skip
-def jruby_skip(message = "")
- skip message if defined?(JRUBY_VERSION)
-end
-
require "active_support/testing/method_call_assertions"
class ForkingExecutor
@@ -438,4 +431,21 @@ end
class ActiveSupport::TestCase
include ActiveSupport::Testing::MethodCallAssertions
+
+ # Skips the current run on Rubinius using Minitest::Assertions#skip
+ private def rubinius_skip(message = "")
+ skip message if RUBY_ENGINE == "rbx"
+ end
+ # Skips the current run on JRuby using Minitest::Assertions#skip
+ private def jruby_skip(message = "")
+ skip message if defined?(JRUBY_VERSION)
+ end
+end
+
+class DrivenByRackTest < ActionDispatch::SystemTestCase
+ driven_by :rack_test
+end
+
+class DrivenBySeleniumWithChrome < ActionDispatch::SystemTestCase
+ driven_by :selenium, using: :chrome
end
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index 9ab152fc5c..73aab5848b 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -83,7 +83,7 @@ class ActionPackAssertionsController < ActionController::Base
end
def render_file_absolute_path
- render file: File.expand_path("../../../README.rdoc", __FILE__)
+ render file: File.expand_path("../../README.rdoc", __dir__)
end
def render_file_relative_path
diff --git a/actionpack/test/controller/api/data_streaming_test.rb b/actionpack/test/controller/api/data_streaming_test.rb
index f15b78d102..e6419b9adf 100644
--- a/actionpack/test/controller/api/data_streaming_test.rb
+++ b/actionpack/test/controller/api/data_streaming_test.rb
@@ -1,7 +1,7 @@
require "abstract_unit"
module TestApiFileUtils
- def file_path() File.expand_path(__FILE__) end
+ def file_path() __FILE__ end
def file_data() @data ||= File.open(file_path, "rb") { |f| f.read } end
end
diff --git a/actionpack/test/controller/api/with_helpers_test.rb b/actionpack/test/controller/api/with_helpers_test.rb
new file mode 100644
index 0000000000..06db949153
--- /dev/null
+++ b/actionpack/test/controller/api/with_helpers_test.rb
@@ -0,0 +1,42 @@
+require "abstract_unit"
+
+module ApiWithHelper
+ def my_helper
+ "helper"
+ end
+end
+
+class WithHelpersController < ActionController::API
+ include ActionController::Helpers
+ helper ApiWithHelper
+
+ def with_helpers
+ render plain: self.class.helpers.my_helper
+ end
+end
+
+class SubclassWithHelpersController < WithHelpersController
+ def with_helpers
+ render plain: self.class.helpers.my_helper
+ end
+end
+
+class WithHelpersTest < ActionController::TestCase
+ tests WithHelpersController
+
+ def test_with_helpers
+ get :with_helpers
+
+ assert_equal "helper", response.body
+ end
+end
+
+class SubclassWithHelpersTest < ActionController::TestCase
+ tests WithHelpersController
+
+ def test_with_helpers
+ get :with_helpers
+
+ assert_equal "helper", response.body
+ end
+end
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index 42a5157010..4e969fac07 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -11,6 +11,12 @@ end
class EmptyController < ActionController::Base
end
+class SimpleController < ActionController::Base
+ def hello
+ self.response_body = "hello"
+ end
+end
+
class NonEmptyController < ActionController::Base
def public_action
head :ok
@@ -118,6 +124,27 @@ class ControllerInstanceTests < ActiveSupport::TestCase
controller = klass.new
assert_equal "examples", controller.controller_path
end
+
+ def test_response_has_default_headers
+ original_default_headers = ActionDispatch::Response.default_headers
+
+ ActionDispatch::Response.default_headers = {
+ "X-Frame-Options" => "DENY",
+ "X-Content-Type-Options" => "nosniff",
+ "X-XSS-Protection" => "1;"
+ }
+
+ response_headers = SimpleController.action("hello").call(
+ "REQUEST_METHOD" => "GET",
+ "rack.input" => -> {}
+ )[1]
+
+ assert response_headers.key?("X-Frame-Options")
+ assert response_headers.key?("X-Content-Type-Options")
+ assert response_headers.key?("X-XSS-Protection")
+ ensure
+ ActionDispatch::Response.default_headers = original_default_headers
+ end
end
class PerformActionTest < ActionController::TestCase
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index fa8d9dc09a..c86dcafee5 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -4,7 +4,7 @@ require "lib/controller/fake_models"
CACHE_DIR = "test_cache"
# Don't change '/../temp/' cavalierly or you might hose something you don't want hosed
-FILE_STORE_PATH = File.join(File.dirname(__FILE__), "/../temp/", CACHE_DIR)
+FILE_STORE_PATH = File.join(__dir__, "../temp/", CACHE_DIR)
class FragmentCachingMetalTestController < ActionController::Metal
abstract!
@@ -26,10 +26,6 @@ class FragmentCachingMetalTest < ActionController::TestCase
@controller.request = @request
@controller.response = @response
end
-
- def test_fragment_cache_key
- assert_equal "views/what a key", @controller.fragment_cache_key("what a key")
- end
end
class CachingController < ActionController::Base
@@ -43,6 +39,8 @@ class FragmentCachingTestController < CachingController
end
class FragmentCachingTest < ActionController::TestCase
+ ModelWithKeyAndVersion = Struct.new(:cache_key, :cache_version)
+
def setup
super
@store = ActiveSupport::Cache::MemoryStore.new
@@ -53,12 +51,25 @@ class FragmentCachingTest < ActionController::TestCase
@controller.params = @params
@controller.request = @request
@controller.response = @response
+
+ @m1v1 = ModelWithKeyAndVersion.new("model/1", "1")
+ @m1v2 = ModelWithKeyAndVersion.new("model/1", "2")
+ @m2v1 = ModelWithKeyAndVersion.new("model/2", "1")
+ @m2v2 = ModelWithKeyAndVersion.new("model/2", "2")
end
def test_fragment_cache_key
- assert_equal "views/what a key", @controller.fragment_cache_key("what a key")
- assert_equal "views/test.host/fragment_caching_test/some_action",
- @controller.fragment_cache_key(controller: "fragment_caching_test", action: "some_action")
+ assert_deprecated do
+ assert_equal "views/what a key", @controller.fragment_cache_key("what a key")
+ assert_equal "views/test.host/fragment_caching_test/some_action",
+ @controller.fragment_cache_key(controller: "fragment_caching_test", action: "some_action")
+ end
+ end
+
+ def test_combined_fragment_cache_key
+ assert_equal [ :views, "what a key" ], @controller.combined_fragment_cache_key("what a key")
+ assert_equal [ :views, "test.host/fragment_caching_test/some_action" ],
+ @controller.combined_fragment_cache_key(controller: "fragment_caching_test", action: "some_action")
end
def test_read_fragment_with_caching_enabled
@@ -72,6 +83,12 @@ class FragmentCachingTest < ActionController::TestCase
assert_nil @controller.read_fragment("name")
end
+ def test_read_fragment_with_versioned_model
+ @controller.write_fragment([ "stuff", @m1v1 ], "hello")
+ assert_equal "hello", @controller.read_fragment([ "stuff", @m1v1 ])
+ assert_nil @controller.read_fragment([ "stuff", @m1v2 ])
+ end
+
def test_fragment_exist_with_caching_enabled
@store.write("views/name", "value")
assert @controller.fragment_exist?("name")
@@ -198,7 +215,7 @@ CACHED
assert_equal expected_body, @response.body
assert_equal "This bit's fragment cached",
- @store.read("views/test.host/functional_caching/fragment_cached/#{template_digest("functional_caching/fragment_cached")}")
+ @store.read("views/functional_caching/fragment_cached:#{template_digest("functional_caching/fragment_cached")}/fragment")
end
def test_fragment_caching_in_partials
@@ -207,7 +224,7 @@ CACHED
assert_match(/Old fragment caching in a partial/, @response.body)
assert_match("Old fragment caching in a partial",
- @store.read("views/test.host/functional_caching/html_fragment_cached_with_partial/#{template_digest("functional_caching/_partial")}"))
+ @store.read("views/functional_caching/_partial:#{template_digest("functional_caching/_partial")}/test.host/functional_caching/html_fragment_cached_with_partial"))
end
def test_skipping_fragment_cache_digesting
@@ -237,7 +254,7 @@ CACHED
assert_match(/Some inline content/, @response.body)
assert_match(/Some cached content/, @response.body)
assert_match("Some cached content",
- @store.read("views/test.host/functional_caching/inline_fragment_cached/#{template_digest("functional_caching/inline_fragment_cached")}"))
+ @store.read("views/functional_caching/inline_fragment_cached:#{template_digest("functional_caching/inline_fragment_cached")}/test.host/functional_caching/inline_fragment_cached"))
end
def test_fragment_cache_instrumentation
@@ -264,7 +281,7 @@ CACHED
assert_equal expected_body, @response.body
assert_equal "<p>ERB</p>",
- @store.read("views/test.host/functional_caching/formatted_fragment_cached/#{template_digest("functional_caching/formatted_fragment_cached")}")
+ @store.read("views/functional_caching/formatted_fragment_cached:#{template_digest("functional_caching/formatted_fragment_cached")}/fragment")
end
def test_xml_formatted_fragment_caching
@@ -275,7 +292,7 @@ CACHED
assert_equal expected_body, @response.body
assert_equal " <p>Builder</p>\n",
- @store.read("views/test.host/functional_caching/formatted_fragment_cached/#{template_digest("functional_caching/formatted_fragment_cached")}")
+ @store.read("views/functional_caching/formatted_fragment_cached:#{template_digest("functional_caching/formatted_fragment_cached")}/fragment")
end
def test_fragment_caching_with_variant
@@ -286,7 +303,7 @@ CACHED
assert_equal expected_body, @response.body
assert_equal "<p>PHONE</p>",
- @store.read("views/test.host/functional_caching/formatted_fragment_cached_with_variant/#{template_digest("functional_caching/formatted_fragment_cached_with_variant")}")
+ @store.read("views/functional_caching/formatted_fragment_cached_with_variant:#{template_digest("functional_caching/formatted_fragment_cached_with_variant")}/fragment")
end
private
@@ -412,7 +429,7 @@ class CollectionCacheTest < ActionController::TestCase
def test_collection_fetches_cached_views
get :index
assert_equal 1, @controller.partial_rendered_times
- assert_customer_cached "david/1", "david, 1"
+ assert_match "david, 1", ActionView::PartialRenderer.collection_cache.read("views/customers/_customer:7c228ab609f0baf0b1f2367469210937/david/1")
get :index
assert_equal 1, @controller.partial_rendered_times
@@ -444,14 +461,8 @@ class CollectionCacheTest < ActionController::TestCase
def test_caching_with_callable_cache_key
get :index_with_callable_cache_key
- assert_customer_cached "cached_david", "david, 1"
+ assert_match "david, 1", ActionView::PartialRenderer.collection_cache.read("views/customers/_customer:7c228ab609f0baf0b1f2367469210937/cached_david")
end
-
- private
- def assert_customer_cached(key, content)
- assert_match content,
- ActionView::PartialRenderer.collection_cache.read("views/#{key}/7c228ab609f0baf0b1f2367469210937")
- end
end
class FragmentCacheKeyTestController < CachingController
@@ -470,11 +481,21 @@ class FragmentCacheKeyTest < ActionController::TestCase
@controller.cache_store = @store
end
- def test_fragment_cache_key
+ def test_combined_fragment_cache_key
@controller.account_id = "123"
- assert_equal "views/v1/123/what a key", @controller.fragment_cache_key("what a key")
+ assert_equal [ :views, "v1", "123", "what a key" ], @controller.combined_fragment_cache_key("what a key")
@controller.account_id = nil
- assert_equal "views/v1//what a key", @controller.fragment_cache_key("what a key")
+ assert_equal [ :views, "v1", "what a key" ], @controller.combined_fragment_cache_key("what a key")
+ end
+
+ def test_combined_fragment_cache_key_with_envs
+ ENV["RAILS_APP_VERSION"] = "55"
+ assert_equal [ :views, "55", "v1", "what a key" ], @controller.combined_fragment_cache_key("what a key")
+
+ ENV["RAILS_CACHE_ID"] = "66"
+ assert_equal [ :views, "66", "v1", "what a key" ], @controller.combined_fragment_cache_key("what a key")
+ ensure
+ ENV["RAILS_CACHE_ID"] = ENV["RAILS_APP_VERSION"] = nil
end
end
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index 90b3f7ea88..5f1463cfa8 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -584,7 +584,7 @@ class FilterTest < ActionController::TestCase
assert @controller.instance_variable_get(:@was_audited)
end
- def test_running_anomolous_yet_valid_condition_actions
+ def test_running_anomalous_yet_valid_condition_actions
test_process(AnomolousYetValidConditionController)
assert_equal %w( ensure_login ), @controller.instance_variable_get(:@ran_filter)
assert @controller.instance_variable_get(:@ran_class_action)
diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb
index 4c6a772062..03dbd63614 100644
--- a/actionpack/test/controller/helper_test.rb
+++ b/actionpack/test/controller/helper_test.rb
@@ -1,6 +1,6 @@
require "abstract_unit"
-ActionController::Base.helpers_path = File.expand_path("../../fixtures/helpers", __FILE__)
+ActionController::Base.helpers_path = File.expand_path("../fixtures/helpers", __dir__)
module Fun
class GamesController < ActionController::Base
@@ -48,7 +48,7 @@ end
class HelpersPathsController < ActionController::Base
paths = ["helpers2_pack", "helpers1_pack"].map do |path|
- File.join(File.expand_path("../../fixtures", __FILE__), path)
+ File.join(File.expand_path("../fixtures", __dir__), path)
end
$:.unshift(*paths)
@@ -61,7 +61,7 @@ class HelpersPathsController < ActionController::Base
end
class HelpersTypoController < ActionController::Base
- path = File.expand_path("../../fixtures/helpers_typo", __FILE__)
+ path = File.expand_path("../fixtures/helpers_typo", __dir__)
$:.unshift(path)
self.helpers_path = path
end
@@ -178,7 +178,7 @@ class HelperTest < ActiveSupport::TestCase
end
def test_all_helpers_with_alternate_helper_dir
- @controller_class.helpers_path = File.expand_path("../../fixtures/alternate_helpers", __FILE__)
+ @controller_class.helpers_path = File.expand_path("../fixtures/alternate_helpers", __dir__)
# Reload helpers
@controller_class._helpers = Module.new
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index cd1415b56c..cb282d4330 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -335,6 +335,18 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
end
end
+ def test_redirect_reset_html_document
+ with_test_route_set do
+ get "/redirect"
+ previous_html_document = html_document
+
+ follow_redirect!
+
+ assert_response :ok
+ refute_same previous_html_document, html_document
+ end
+ end
+
def test_xml_http_request_get
with_test_route_set do
get "/get", xhr: true
@@ -494,7 +506,7 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
assert_includes @response.headers, "c"
end
- def test_accept_not_overriden_when_xhr_true
+ def test_accept_not_overridden_when_xhr_true
with_test_route_set do
get "/get", headers: { "Accept" => "application/json" }, xhr: true
assert_equal "application/json", request.accept
@@ -1091,7 +1103,7 @@ class IntegrationFileUploadTest < ActionDispatch::IntegrationTest
end
def self.fixture_path
- File.dirname(__FILE__) + "/../fixtures/multipart"
+ File.expand_path("../fixtures/multipart", __dir__)
end
routes.draw do
diff --git a/actionpack/test/controller/live_stream_test.rb b/actionpack/test/controller/live_stream_test.rb
index e76628b936..bfb47b90d5 100644
--- a/actionpack/test/controller/live_stream_test.rb
+++ b/actionpack/test/controller/live_stream_test.rb
@@ -1,4 +1,5 @@
require "abstract_unit"
+require "timeout"
require "concurrent/atomic/count_down_latch"
Thread.abort_on_exception = true
@@ -151,7 +152,7 @@ module ActionController
end
def write_sleep_autoload
- path = File.join(File.dirname(__FILE__), "../fixtures")
+ path = File.expand_path("../fixtures", __dir__)
ActiveSupport::Dependencies.autoload_paths << path
response.headers["Content-Type"] = "text/event-stream"
diff --git a/actionpack/test/controller/metal_test.rb b/actionpack/test/controller/metal_test.rb
new file mode 100644
index 0000000000..e16452ed6f
--- /dev/null
+++ b/actionpack/test/controller/metal_test.rb
@@ -0,0 +1,30 @@
+require "abstract_unit"
+
+class MetalControllerInstanceTests < ActiveSupport::TestCase
+ class SimpleController < ActionController::Metal
+ def hello
+ self.response_body = "hello"
+ end
+ end
+
+ def test_response_has_default_headers
+ original_default_headers = ActionDispatch::Response.default_headers
+
+ ActionDispatch::Response.default_headers = {
+ "X-Frame-Options" => "DENY",
+ "X-Content-Type-Options" => "nosniff",
+ "X-XSS-Protection" => "1;"
+ }
+
+ response_headers = SimpleController.action("hello").call(
+ "REQUEST_METHOD" => "GET",
+ "rack.input" => -> {}
+ )[1]
+
+ refute response_headers.key?("X-Frame-Options")
+ refute response_headers.key?("X-Content-Type-Options")
+ refute response_headers.key?("X-XSS-Protection")
+ ensure
+ ActionDispatch::Response.default_headers = original_default_headers
+ end
+end
diff --git a/actionpack/test/controller/mime/accept_format_test.rb b/actionpack/test/controller/mime/accept_format_test.rb
index a22fa39051..d1c4dbfef7 100644
--- a/actionpack/test/controller/mime/accept_format_test.rb
+++ b/actionpack/test/controller/mime/accept_format_test.rb
@@ -29,7 +29,7 @@ class StarStarMimeControllerTest < ActionController::TestCase
end
class AbstractPostController < ActionController::Base
- self.view_paths = File.dirname(__FILE__) + "/../../fixtures/post_test/"
+ self.view_paths = File.expand_path("../../fixtures/post_test", __dir__)
end
# For testing layouts which are set automatically
diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb
index 818dc119eb..61bd5c80c4 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -519,7 +519,7 @@ class RespondToControllerTest < ActionController::TestCase
assert_equal "Whatever you ask for, I got it", @response.body
end
- def test_handle_any_any_unkown_format
+ def test_handle_any_any_unknown_format
get :handle_any_any, format: "php"
assert_equal "Whatever you ask for, I got it", @response.body
end
diff --git a/actionpack/test/controller/new_base/render_file_test.rb b/actionpack/test/controller/new_base/render_file_test.rb
index 6d651e0104..4491dd96ed 100644
--- a/actionpack/test/controller/new_base/render_file_test.rb
+++ b/actionpack/test/controller/new_base/render_file_test.rb
@@ -2,15 +2,15 @@ require "abstract_unit"
module RenderFile
class BasicController < ActionController::Base
- self.view_paths = File.dirname(__FILE__)
+ self.view_paths = __dir__
def index
- render file: File.join(File.dirname(__FILE__), *%w[.. .. fixtures test hello_world])
+ render file: File.expand_path("../../fixtures/test/hello_world", __dir__)
end
def with_instance_variables
@secret = "in the sauce"
- render file: File.join(File.dirname(__FILE__), "../../fixtures/test/render_file_with_ivar")
+ render file: File.expand_path("../../fixtures/test/render_file_with_ivar", __dir__)
end
def relative_path
@@ -25,11 +25,11 @@ module RenderFile
def pathname
@secret = "in the sauce"
- render file: Pathname.new(File.dirname(__FILE__)).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar])
+ render file: Pathname.new(__dir__).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar])
end
def with_locals
- path = File.join(File.dirname(__FILE__), "../../fixtures/test/render_file_with_locals")
+ path = File.expand_path("../../fixtures/test/render_file_with_locals", __dir__)
render file: path, locals: { secret: "in the sauce" }
end
end
diff --git a/actionpack/test/controller/new_base/render_implicit_action_test.rb b/actionpack/test/controller/new_base/render_implicit_action_test.rb
index 796283466a..c5fc8e15e1 100644
--- a/actionpack/test/controller/new_base/render_implicit_action_test.rb
+++ b/actionpack/test/controller/new_base/render_implicit_action_test.rb
@@ -6,7 +6,7 @@ module RenderImplicitAction
"render_implicit_action/simple/hello_world.html.erb" => "Hello world!",
"render_implicit_action/simple/hyphen-ated.html.erb" => "Hello hyphen-ated!",
"render_implicit_action/simple/not_implemented.html.erb" => "Not Implemented"
- ), ActionView::FileSystemResolver.new(File.expand_path("../../../controller", __FILE__))]
+ ), ActionView::FileSystemResolver.new(File.expand_path("../../controller", __dir__))]
def hello_world() end
end
diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb
index 2893eb7b91..87407a4272 100644
--- a/actionpack/test/controller/parameters/accessors_test.rb
+++ b/actionpack/test/controller/parameters/accessors_test.rb
@@ -35,6 +35,11 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
assert @params.as_json.key? "person"
end
+ test "to_s returns the string representation of the parameters hash" do
+ assert_equal '{"person"=>{"age"=>"32", "name"=>{"first"=>"David", "last"=>"Heinemeier Hansson"}, ' \
+ '"addresses"=>[{"city"=>"Chicago", "state"=>"Illinois"}]}}', @params.to_s
+ end
+
test "each carries permitted status" do
@params.permit!
@params.each { |key, value| assert(value.permitted?) if key == "person" }
@@ -53,6 +58,15 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
@params.each_pair { |key, value| assert_not(value.permitted?) if key == "person" }
end
+ test "empty? returns true when params contains no key/value pairs" do
+ params = ActionController::Parameters.new
+ assert params.empty?
+ end
+
+ test "empty? returns false when any params are present" do
+ refute @params.empty?
+ end
+
test "except retains permitted status" do
@params.permit!
assert @params.except(:person).permitted?
@@ -75,6 +89,45 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
assert_not @params[:person].fetch(:name).permitted?
end
+ test "has_key? returns true if the given key is present in the params" do
+ assert @params.has_key?(:person)
+ end
+
+ test "has_key? returns false if the given key is not present in the params" do
+ refute @params.has_key?(:address)
+ end
+
+ test "has_value? returns true if the given value is present in the params" do
+ params = ActionController::Parameters.new(city: "Chicago", state: "Illinois")
+ assert params.has_value?("Chicago")
+ end
+
+ test "has_value? returns false if the given value is not present in the params" do
+ params = ActionController::Parameters.new(city: "Chicago", state: "Illinois")
+ refute params.has_value?("New York")
+ end
+
+ test "include? returns true if the given key is present in the params" do
+ assert @params.include?(:person)
+ end
+
+ test "include? returns false if the given key is not present in the params" do
+ refute @params.include?(:address)
+ end
+
+ test "key? returns true if the given key is present in the params" do
+ assert @params.key?(:person)
+ end
+
+ test "key? returns false if the given key is not present in the params" do
+ refute @params.key?(:address)
+ end
+
+ test "keys returns an array of the keys of the params" do
+ assert_equal ["person"], @params.keys
+ assert_equal ["age", "name", "addresses"], @params[:person].keys
+ end
+
test "reject retains permitted status" do
assert_not @params.reject { |k| k == "person" }.permitted?
end
@@ -120,6 +173,21 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
assert_not @params.transform_values { |v| v }.permitted?
end
+ test "value? returns true if the given value is present in the params" do
+ params = ActionController::Parameters.new(city: "Chicago", state: "Illinois")
+ assert params.value?("Chicago")
+ end
+
+ test "value? returns false if the given value is not present in the params" do
+ params = ActionController::Parameters.new(city: "Chicago", state: "Illinois")
+ refute params.value?("New York")
+ end
+
+ test "values returns an array of the values of the params" do
+ params = ActionController::Parameters.new(city: "Chicago", state: "Illinois")
+ assert_equal ["Chicago", "Illinois"], params.values
+ end
+
test "values_at retains permitted status" do
@params.permit!
assert @params.values_at(:person).first.permitted?
diff --git a/actionpack/test/controller/parameters/mutators_test.rb b/actionpack/test/controller/parameters/mutators_test.rb
index e61bbdbe13..3fe7340782 100644
--- a/actionpack/test/controller/parameters/mutators_test.rb
+++ b/actionpack/test/controller/parameters/mutators_test.rb
@@ -25,6 +25,27 @@ class ParametersMutatorsTest < ActiveSupport::TestCase
assert_not @params.delete(:person).permitted?
end
+ test "delete returns the value when the key is present" do
+ assert_equal "32", @params[:person].delete(:age)
+ end
+
+ test "delete removes the entry when the key present" do
+ @params[:person].delete(:age)
+ assert_not @params[:person].key?(:age)
+ end
+
+ test "delete returns nil when the key is not present" do
+ assert_nil @params[:person].delete(:first_name)
+ end
+
+ test "delete returns the value of the given block when the key is not present" do
+ assert_equal "David", @params[:person].delete(:first_name) { "David" }
+ end
+
+ test "delete yields the key to the given block when the key is not present" do
+ assert_equal "first_name: David", @params[:person].delete(:first_name) { |k| "#{k}: David" }
+ end
+
test "delete_if retains permitted status" do
@params.permit!
assert @params.delete_if { |k| k == "person" }.permitted?
diff --git a/actionpack/test/controller/parameters/nested_parameters_permit_test.rb b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
index 5f86901e30..00e591d5a7 100644
--- a/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb
@@ -140,6 +140,11 @@ class NestedParametersPermitTest < ActiveSupport::TestCase
assert_equal "William Shakespeare", permitted[:book][:authors_attributes]["0"][:name]
assert_equal "Unattributed Assistant", permitted[:book][:authors_attributes]["1"][:name]
+ assert_equal(
+ { "book" => { "authors_attributes" => { "0" => { "name" => "William Shakespeare" }, "1" => { "name" => "Unattributed Assistant" }, "2" => {} } } },
+ permitted.to_h
+ )
+
assert_filtered_out permitted[:book][:authors_attributes]["0"], :age_of_death
end
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index b62a3d6d7b..ae2b45c9f0 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -66,12 +66,20 @@ class ParametersPermitTest < ActiveSupport::TestCase
values.each do |value|
params = ActionController::Parameters.new(id: value)
permitted = params.permit(:id)
- assert_equal value, permitted[:id]
+ if value.nil?
+ assert_nil permitted[:id]
+ else
+ assert_equal value, permitted[:id]
+ end
@struct_fields.each do |sf|
params = ActionController::Parameters.new(sf => value)
permitted = params.permit(:sf)
- assert_equal value, permitted[sf]
+ if value.nil?
+ assert_nil permitted[sf]
+ else
+ assert_equal value, permitted[sf]
+ end
end
end
end
@@ -187,11 +195,6 @@ class ParametersPermitTest < ActiveSupport::TestCase
permitted = params.permit(:username, preferences: {}, hacked: {})
- assert permitted.permitted?
- assert permitted[:preferences].permitted?
- assert permitted[:preferences][:font].permitted?
- assert permitted[:preferences][:dubious].all?(&:permitted?)
-
assert_equal "fxn", permitted[:username]
assert_equal "Marazul", permitted[:preferences][:scheme]
assert_equal "Source Code Pro", permitted[:preferences][:font][:name]
@@ -299,6 +302,47 @@ class ParametersPermitTest < ActiveSupport::TestCase
assert_equal "32", @params[:person][:age]
end
+ test "#reverse_merge with parameters" do
+ default_params = ActionController::Parameters.new(id: "1234", person: {}).permit!
+ merged_params = @params.reverse_merge(default_params)
+
+ assert_equal "1234", merged_params[:id]
+ refute_predicate merged_params[:person], :empty?
+ end
+
+ test "#with_defaults is an alias of reverse_merge" do
+ default_params = ActionController::Parameters.new(id: "1234", person: {}).permit!
+ merged_params = @params.with_defaults(default_params)
+
+ assert_equal "1234", merged_params[:id]
+ refute_predicate merged_params[:person], :empty?
+ end
+
+ test "not permitted is sticky beyond reverse_merge" do
+ refute_predicate @params.reverse_merge(a: "b"), :permitted?
+ end
+
+ test "permitted is sticky beyond reverse_merge" do
+ @params.permit!
+ assert_predicate @params.reverse_merge(a: "b"), :permitted?
+ end
+
+ test "#reverse_merge! with parameters" do
+ default_params = ActionController::Parameters.new(id: "1234", person: {}).permit!
+ @params.reverse_merge!(default_params)
+
+ assert_equal "1234", @params[:id]
+ refute_predicate @params[:person], :empty?
+ end
+
+ test "#with_defaults! is an alias of reverse_merge!" do
+ default_params = ActionController::Parameters.new(id: "1234", person: {}).permit!
+ @params.with_defaults!(default_params)
+
+ assert_equal "1234", @params[:id]
+ refute_predicate @params[:person], :empty?
+ end
+
test "modifying the parameters" do
@params[:person][:hometown] = "Chicago"
@params[:person][:family] = { brother: "Jonas" }
@@ -333,17 +377,17 @@ class ParametersPermitTest < ActiveSupport::TestCase
assert_equal "32", @params[:person].permit([ :age ])[:age]
end
- test "to_h returns empty hash on unpermitted params" do
- assert @params.to_h.is_a? ActiveSupport::HashWithIndifferentAccess
- assert_not @params.to_h.is_a? ActionController::Parameters
- assert @params.to_h.empty?
+ test "to_h raises UnfilteredParameters on unfiltered params" do
+ assert_raises(ActionController::UnfilteredParameters) do
+ @params.to_h
+ end
end
test "to_h returns converted hash on permitted params" do
@params.permit!
- assert @params.to_h.is_a? ActiveSupport::HashWithIndifferentAccess
- assert_not @params.to_h.is_a? ActionController::Parameters
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, @params.to_h
+ assert_not_kind_of ActionController::Parameters, @params.to_h
end
test "to_h returns converted hash when .permit_all_parameters is set" do
@@ -351,39 +395,71 @@ class ParametersPermitTest < ActiveSupport::TestCase
ActionController::Parameters.permit_all_parameters = true
params = ActionController::Parameters.new(crab: "Senjougahara Hitagi")
- assert params.to_h.is_a? ActiveSupport::HashWithIndifferentAccess
- assert_not @params.to_h.is_a? ActionController::Parameters
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, params.to_h
+ assert_not_kind_of ActionController::Parameters, params.to_h
assert_equal({ "crab" => "Senjougahara Hitagi" }, params.to_h)
ensure
ActionController::Parameters.permit_all_parameters = false
end
end
- test "to_h returns always permitted parameter on unpermitted params" do
- params = ActionController::Parameters.new(
- controller: "users",
- action: "create",
- user: {
- name: "Sengoku Nadeko"
- }
- )
+ test "to_hash raises UnfilteredParameters on unfiltered params" do
+ assert_raises(ActionController::UnfilteredParameters) do
+ @params.to_hash
+ end
+ end
+
+ test "to_hash returns converted hash on permitted params" do
+ @params.permit!
+
+ assert_instance_of Hash, @params.to_hash
+ assert_not_kind_of ActionController::Parameters, @params.to_hash
+ end
+
+ test "parameters can be implicit converted to Hash" do
+ params = ActionController::Parameters.new
+ params.permit!
+
+ assert_equal({ a: 1 }, { a: 1 }.merge!(params))
+ end
- assert_equal({ "controller" => "users", "action" => "create" }, params.to_h)
+ test "to_hash returns converted hash when .permit_all_parameters is set" do
+ begin
+ ActionController::Parameters.permit_all_parameters = true
+ params = ActionController::Parameters.new(crab: "Senjougahara Hitagi")
+
+ assert_instance_of Hash, params.to_hash
+ assert_not_kind_of ActionController::Parameters, params.to_hash
+ assert_equal({ "crab" => "Senjougahara Hitagi" }, params.to_hash)
+ assert_equal({ "crab" => "Senjougahara Hitagi" }, params)
+ ensure
+ ActionController::Parameters.permit_all_parameters = false
+ end
end
test "to_unsafe_h returns unfiltered params" do
- assert @params.to_unsafe_h.is_a? ActiveSupport::HashWithIndifferentAccess
- assert_not @params.to_unsafe_h.is_a? ActionController::Parameters
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, @params.to_unsafe_h
+ assert_not_kind_of ActionController::Parameters, @params.to_unsafe_h
end
test "to_unsafe_h returns unfiltered params even after accessing few keys" do
params = ActionController::Parameters.new("f" => { "language_facet" => ["Tibetan"] })
expected = { "f" => { "language_facet" => ["Tibetan"] } }
- assert params["f"].is_a? ActionController::Parameters
+ assert_instance_of ActionController::Parameters, params["f"]
assert_equal expected, params.to_unsafe_h
end
+ test "to_unsafe_h does not mutate the parameters" do
+ params = ActionController::Parameters.new("f" => { "language_facet" => ["Tibetan"] })
+ params[:f]
+
+ params.to_unsafe_h
+
+ assert_not_predicate params, :permitted?
+ assert_not_predicate params[:f], :permitted?
+ end
+
test "to_h only deep dups Ruby collections" do
company = Class.new do
attr_reader :dupped
diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb
index faa57c4559..c0f01e6df8 100644
--- a/actionpack/test/controller/params_wrapper_test.rb
+++ b/actionpack/test/controller/params_wrapper_test.rb
@@ -32,6 +32,10 @@ class ParamsWrapperTest < ActionController::TestCase
def self.attribute_names
[]
end
+
+ def self.stored_attributes
+ { settings: [:color, :size] }
+ end
end
class Person
@@ -62,6 +66,17 @@ class ParamsWrapperTest < ActionController::TestCase
end
end
+ def test_store_accessors_wrapped
+ assert_called(User, :attribute_names, times: 2, returns: ["username"]) do
+ with_default_wrapper_options do
+ @request.env["CONTENT_TYPE"] = "application/json"
+ post :parse, params: { "username" => "sikachu", "color" => "blue", "size" => "large" }
+ assert_parameters("username" => "sikachu", "color" => "blue", "size" => "large",
+ "user" => { "username" => "sikachu", "color" => "blue", "size" => "large" })
+ end
+ end
+ end
+
def test_specify_wrapper_name
with_default_wrapper_options do
UsersController.wrap_parameters :person
@@ -155,6 +170,14 @@ class ParamsWrapperTest < ActionController::TestCase
end
end
+ def test_no_double_wrap_if_key_exists_and_value_is_nil
+ with_default_wrapper_options do
+ @request.env["CONTENT_TYPE"] = "application/json"
+ post :parse, params: { "user" => nil }
+ assert_parameters("user" => nil)
+ end
+ end
+
def test_nested_params
with_default_wrapper_options do
@request.env["CONTENT_TYPE"] = "application/json"
@@ -203,6 +226,14 @@ class ParamsWrapperTest < ActionController::TestCase
end
end
+ def test_preserves_query_string_params_in_filtered_params
+ with_default_wrapper_options do
+ @request.env["CONTENT_TYPE"] = "application/json"
+ get :parse, params: { "user" => { "username" => "nixon" } }
+ assert_equal({ "controller" => "params_wrapper_test/users", "action" => "parse", "user" => { "username" => "nixon" } }, @request.filtered_parameters)
+ end
+ end
+
def test_empty_parameter_set
with_default_wrapper_options do
@request.env["CONTENT_TYPE"] = "application/json"
diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb
index e4e968dfdb..5b16af78c4 100644
--- a/actionpack/test/controller/redirect_test.rb
+++ b/actionpack/test/controller/redirect_test.rb
@@ -21,8 +21,8 @@ end
class RedirectController < ActionController::Base
# empty method not used anywhere to ensure methods like
# `status` and `location` aren't called on `redirect_to` calls
- def status; render plain: "called status"; end
- def location; render plain: "called location"; end
+ def status; raise "Should not be called!"; end
+ def location; raise "Should not be called!"; end
def simple_redirect
redirect_to action: "hello_world"
@@ -285,10 +285,10 @@ class RedirectTest < ActionController::TestCase
end
def test_redirect_to_params
- error = assert_raise(ArgumentError) do
+ error = assert_raise(ActionController::UnfilteredParameters) do
get :redirect_to_params
end
- assert_equal ActionDispatch::Routing::INSECURE_URL_PARAMETERS_MESSAGE, error.message
+ assert_equal "unable to convert unpermitted parameters to hash", error.message
end
def test_redirect_to_with_block
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 0c0f18f200..17d834d55f 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -257,7 +257,7 @@ end
module TemplateModificationHelper
private
def modify_template(name)
- path = File.expand_path("../../fixtures/#{name}.erb", __FILE__)
+ path = File.expand_path("../fixtures/#{name}.erb", __dir__)
original = File.read(path)
File.write(path, "#{original} Modified!")
ActionView::LookupContext::DetailsKey.clear
@@ -287,9 +287,9 @@ class ExpiresInRenderTest < ActionController::TestCase
def test_dynamic_render_with_file
# This is extremely bad, but should be possible to do.
- assert File.exist?(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb"))
+ assert File.exist?(File.expand_path("../../test/abstract_unit.rb", __dir__))
response = get :dynamic_render_with_file, params: { id: '../\\../test/abstract_unit.rb' }
- assert_equal File.read(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")),
+ assert_equal File.read(File.expand_path("../../test/abstract_unit.rb", __dir__)),
response.body
end
@@ -306,17 +306,16 @@ class ExpiresInRenderTest < ActionController::TestCase
end
def test_dynamic_render
- assert File.exist?(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb"))
+ assert File.exist?(File.expand_path("../../test/abstract_unit.rb", __dir__))
assert_raises ActionView::MissingTemplate do
get :dynamic_render, params: { id: '../\\../test/abstract_unit.rb' }
end
end
def test_permitted_dynamic_render_file_hash
- skip "FIXME: this test passes on 4-2-stable but not master. Why?"
- assert File.exist?(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb"))
+ assert File.exist?(File.expand_path("../../test/abstract_unit.rb", __dir__))
response = get :dynamic_render_permit, params: { id: { file: '../\\../test/abstract_unit.rb' } }
- assert_equal File.read(File.join(File.dirname(__FILE__), "../../test/abstract_unit.rb")),
+ assert_equal File.read(File.expand_path("../../test/abstract_unit.rb", __dir__)),
response.body
end
diff --git a/actionpack/test/controller/renderer_test.rb b/actionpack/test/controller/renderer_test.rb
index 866600b935..052c974d68 100644
--- a/actionpack/test/controller/renderer_test.rb
+++ b/actionpack/test/controller/renderer_test.rb
@@ -19,6 +19,16 @@ class RendererTest < ActiveSupport::TestCase
assert_equal controller, renderer.controller
end
+ test "creating with new defaults" do
+ renderer = ApplicationController.renderer
+
+ new_defaults = { https: true }
+ new_renderer = renderer.with_defaults(new_defaults).new
+ content = new_renderer.render(inline: "<%= request.ssl? %>")
+
+ assert_equal "true", content
+ end
+
test "rendering with a class renderer" do
renderer = ApplicationController.renderer
content = renderer.render template: "ruby_template"
@@ -103,6 +113,20 @@ class RendererTest < ActiveSupport::TestCase
assert_equal "true", content
end
+ test "return valid asset url with defaults" do
+ renderer = ApplicationController.renderer
+ content = renderer.render inline: "<%= asset_url 'asset.jpg' %>"
+
+ assert_equal "http://example.org/asset.jpg", content
+ end
+
+ test "return valid asset url when https is true" do
+ renderer = ApplicationController.renderer.new https: true
+ content = renderer.render inline: "<%= asset_url 'asset.jpg' %>"
+
+ assert_equal "https://example.org/asset.jpg", content
+ end
+
private
def render
@render ||= ApplicationController.renderer.method(:render)
diff --git a/actionpack/test/controller/request/test_request_test.rb b/actionpack/test/controller/request/test_request_test.rb
index b67ae72c0a..1440db00f6 100644
--- a/actionpack/test/controller/request/test_request_test.rb
+++ b/actionpack/test/controller/request/test_request_test.rb
@@ -21,16 +21,20 @@ class ActionController::TestRequestTest < ActionController::TestCase
@request.get_header("CONTENT_LENGTH"))
end
- ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_key do |option|
- test "rack default session options #{option} exists in session options and is default" do
- assert_equal(ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS[option],
- @request.session_options[option],
- "Missing rack session default option #{option} in request.session_options")
+ ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_pair do |key, value|
+ test "rack default session options #{key} exists in session options and is default" do
+ if value.nil?
+ assert_nil(@request.session_options[key],
+ "Missing rack session default option #{key} in request.session_options")
+ else
+ assert_equal(value, @request.session_options[key],
+ "Missing rack session default option #{key} in request.session_options")
+ end
end
- test "rack default session options #{option} exists in session options" do
- assert(@request.session_options.has_key?(option),
- "Missing rack session option #{option} in request.session_options")
+ test "rack default session options #{key} exists in session options" do
+ assert(@request.session_options.has_key?(key),
+ "Missing rack session option #{key} in request.session_options")
end
end
end
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index d645ddfdbe..4d441ab1a9 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -35,6 +35,22 @@ module RequestForgeryProtectionActions
render inline: "<%= form_for(:some_resource, :remote => true, :authenticity_token => 'external_token') {} %>"
end
+ def form_with_remote
+ render inline: "<%= form_with(scope: :some_resource) {} %>"
+ end
+
+ def form_with_remote_with_token
+ render inline: "<%= form_with(scope: :some_resource, authenticity_token: true) {} %>"
+ end
+
+ def form_with_local_with_token
+ render inline: "<%= form_with(scope: :some_resource, local: true, authenticity_token: true) {} %>"
+ end
+
+ def form_with_remote_with_external_token
+ render inline: "<%= form_with(scope: :some_resource, authenticity_token: 'external_token') {} %>"
+ end
+
def same_origin_js
render js: "foo();"
end
@@ -147,6 +163,13 @@ class PerFormTokensController < ActionController::Base
end
end
+class SkipProtectionController < ActionController::Base
+ include RequestForgeryProtectionActions
+ protect_from_forgery with: :exception
+ skip_forgery_protection if: :skip_requested
+ attr_accessor :skip_requested
+end
+
# common test methods
module RequestForgeryProtectionTests
def setup
@@ -235,6 +258,80 @@ module RequestForgeryProtectionTests
end
end
+ def test_should_render_form_with_with_token_tag_if_remote
+ assert_not_blocked do
+ get :form_with_remote
+ end
+ assert_match(/authenticity_token/, response.body)
+ end
+
+ def test_should_render_form_with_without_token_tag_if_remote_and_embedding_token_is_off
+ original = ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms
+ begin
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = false
+ assert_not_blocked do
+ get :form_with_remote
+ end
+ assert_no_match(/authenticity_token/, response.body)
+ ensure
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = original
+ end
+ end
+
+ def test_should_render_form_with_with_token_tag_if_remote_and_external_authenticity_token_requested_and_embedding_is_on
+ original = ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms
+ begin
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = true
+ assert_not_blocked do
+ get :form_with_remote_with_external_token
+ end
+ assert_select "form>input[name=?][value=?]", "custom_authenticity_token", "external_token"
+ ensure
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = original
+ end
+ end
+
+ def test_should_render_form_with_with_token_tag_if_remote_and_external_authenticity_token_requested
+ assert_not_blocked do
+ get :form_with_remote_with_external_token
+ end
+ assert_select "form>input[name=?][value=?]", "custom_authenticity_token", "external_token"
+ end
+
+ def test_should_render_form_with_with_token_tag_if_remote_and_authenticity_token_requested
+ @controller.stub :form_authenticity_token, @token do
+ assert_not_blocked do
+ get :form_with_remote_with_token
+ end
+ assert_select "form>input[name=?][value=?]", "custom_authenticity_token", @token
+ end
+ end
+
+ def test_should_render_form_with_with_token_tag_with_authenticity_token_requested
+ @controller.stub :form_authenticity_token, @token do
+ assert_not_blocked do
+ get :form_with_local_with_token
+ end
+ assert_select "form>input[name=?][value=?]", "custom_authenticity_token", @token
+ end
+ end
+
+ def test_should_render_form_with_with_token_tag_if_remote_and_embedding_token_is_on
+ original = ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms
+ begin
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = true
+
+ @controller.stub :form_authenticity_token, @token do
+ assert_not_blocked do
+ get :form_with_remote
+ end
+ end
+ assert_select "form>input[name=?][value=?]", "custom_authenticity_token", @token
+ ensure
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = original
+ end
+ end
+
def test_should_allow_get
assert_not_blocked { get :index }
end
@@ -347,6 +444,10 @@ module RequestForgeryProtectionTests
end
def test_should_block_post_with_origin_checking_and_wrong_origin
+ old_logger = ActionController::Base.logger
+ logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new
+ ActionController::Base.logger = logger
+
forgery_protection_origin_check do
session[:_csrf_token] = @token
@controller.stub :form_authenticity_token, @token do
@@ -356,6 +457,13 @@ module RequestForgeryProtectionTests
end
end
end
+
+ assert_match(
+ "HTTP Origin header (http://bad.host) didn't match request.base_url (http://test.host)",
+ logger.logged(:warn).last
+ )
+ ensure
+ ActionController::Base.logger = old_logger
end
def test_should_warn_on_missing_csrf_token
@@ -863,3 +971,26 @@ class PerFormTokensControllerTest < ActionController::TestCase
assert_equal expected, actual
end
end
+
+class SkipProtectionControllerTest < ActionController::TestCase
+ def test_should_not_allow_post_without_token_when_not_skipping
+ @controller.skip_requested = false
+ assert_blocked { post :index }
+ end
+
+ def test_should_allow_post_without_token_when_skipping
+ @controller.skip_requested = true
+ assert_not_blocked { post :index }
+ end
+
+ def assert_blocked
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ yield
+ end
+ end
+
+ def assert_not_blocked
+ assert_nothing_raised { yield }
+ assert_response :success
+ end
+end
diff --git a/actionpack/test/controller/required_params_test.rb b/actionpack/test/controller/required_params_test.rb
index dd07c2486b..46bb374b3f 100644
--- a/actionpack/test/controller/required_params_test.rb
+++ b/actionpack/test/controller/required_params_test.rb
@@ -72,9 +72,27 @@ class ParametersRequireTest < ActiveSupport::TestCase
assert params.value?("cinco")
end
- test "to_query is not supported" do
- assert_raises(NoMethodError) do
- ActionController::Parameters.new(foo: "bar").to_param
+ test "to_param works like in a Hash" do
+ params = ActionController::Parameters.new(nested: { key: "value" }).permit!
+ assert_equal({ nested: { key: "value" } }.to_param, params.to_param)
+
+ params = { root: ActionController::Parameters.new(nested: { key: "value" }).permit! }
+ assert_equal({ root: { nested: { key: "value" } } }.to_param, params.to_param)
+
+ assert_raise(ActionController::UnfilteredParameters) do
+ ActionController::Parameters.new(nested: { key: "value" }).to_param
+ end
+ end
+
+ test "to_query works like in a Hash" do
+ params = ActionController::Parameters.new(nested: { key: "value" }).permit!
+ assert_equal({ nested: { key: "value" } }.to_query, params.to_query)
+
+ params = { root: ActionController::Parameters.new(nested: { key: "value" }).permit! }
+ assert_equal({ root: { nested: { key: "value" } } }.to_query, params.to_query)
+
+ assert_raise(ActionController::UnfilteredParameters) do
+ ActionController::Parameters.new(nested: { key: "value" }).to_query
end
end
end
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index 56b39510bb..fefb84e095 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "abstract_unit"
require "controller/fake_controllers"
require "active_support/core_ext/object/with_options"
@@ -656,7 +658,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
assert_equal "/page/foo", url_for(rs, controller: "content", action: "show_page", id: "foo")
assert_equal({ controller: "content", action: "show_page", id: "foo" }, rs.recognize_path("/page/foo"))
- token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in Russian
+ token = "\321\202\320\265\320\272\321\201\321\202".dup # 'text' in Russian
token.force_encoding(Encoding::BINARY)
escaped_token = CGI::escape(token)
diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb
index 9e6b975fe2..e265c6c49c 100644
--- a/actionpack/test/controller/send_file_test.rb
+++ b/actionpack/test/controller/send_file_test.rb
@@ -2,7 +2,7 @@ require "abstract_unit"
module TestFileUtils
def file_name() File.basename(__FILE__) end
- def file_path() File.expand_path(__FILE__) end
+ def file_path() __FILE__ end
def file_data() @data ||= File.open(file_path, "rb") { |f| f.read } end
end
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 874f9c3c42..677e2ddded 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -122,7 +122,7 @@ XML
end
def test_send_file
- send_file(File.expand_path(__FILE__))
+ send_file(__FILE__)
end
def redirect_to_same_controller
@@ -134,7 +134,7 @@ XML
end
def create
- head :created, location: "created resource"
+ head :created, location: "/resource"
end
def render_cookie
@@ -679,6 +679,11 @@ XML
assert_equal "baz", @request.filtered_parameters[:foo]
end
+ def test_path_is_kept_after_the_request
+ get :test_params, params: { id: "foo" }
+ assert_equal "/test_case_test/test/test_params/foo", @request.path
+ end
+
def test_path_params_reset_between_request
get :test_params, params: { id: "foo" }
assert_equal "foo", @request.path_parameters[:id]
@@ -775,7 +780,7 @@ XML
end
end
- FILES_DIR = File.dirname(__FILE__) + "/../fixtures/multipart"
+ FILES_DIR = File.expand_path("../fixtures/multipart", __dir__)
READ_BINARY = "rb:binary"
READ_PLAIN = "r:binary"
@@ -796,7 +801,6 @@ XML
new_content_type = "new content_type"
file.content_type = new_content_type
assert_equal new_content_type, file.content_type
-
end
def test_fixture_path_is_accessed_from_self_instead_of_active_support_test_case
@@ -851,7 +855,7 @@ XML
end
def test_fixture_file_upload_ignores_fixture_path_given_full_path
- TestCaseTest.stub :fixture_path, File.dirname(__FILE__) do
+ TestCaseTest.stub :fixture_path, __dir__ do
uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpg")
assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read
end
@@ -880,12 +884,12 @@ XML
assert_response :created
# Redirect url doesn't care that it wasn't a :redirect response.
- assert_equal "created resource", @response.redirect_url
+ assert_equal "/resource", @response.redirect_url
assert_equal @response.redirect_url, redirect_to_url
# Must be a :redirect response.
assert_raise(ActiveSupport::TestCase::Assertion) do
- assert_redirected_to "created resource"
+ assert_redirected_to "/resource"
end
end
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 862dcf01c3..2afe67ed91 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -386,7 +386,7 @@ module AbstractController
def test_url_action_controller_parameters
add_host!
- assert_raise(ArgumentError) do
+ assert_raise(ActionController::UnfilteredParameters) do
W.new.url_for(ActionController::Parameters.new(controller: "c", action: "a", protocol: "javascript", f: "%0Aeval(name)"))
end
end
diff --git a/actionpack/test/dispatch/callbacks_test.rb b/actionpack/test/dispatch/callbacks_test.rb
index 57e21a22c6..29a5dfc0ad 100644
--- a/actionpack/test/dispatch/callbacks_test.rb
+++ b/actionpack/test/dispatch/callbacks_test.rb
@@ -35,24 +35,6 @@ class DispatcherTest < ActiveSupport::TestCase
assert_equal 6, Foo.b
end
- def test_to_prepare_and_cleanup_delegation
- prepared = cleaned = false
- assert_deprecated do
- ActionDispatch::Callbacks.to_prepare { prepared = true }
- ActionDispatch::Callbacks.to_prepare { cleaned = true }
- end
-
- assert_deprecated do
- ActionDispatch::Reloader.prepare!
- end
- assert prepared
-
- assert_deprecated do
- ActionDispatch::Reloader.cleanup!
- end
- assert cleaned
- end
-
private
def dispatch(&block)
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 664faa31bb..e5646de82e 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -288,8 +288,7 @@ class CookiesTest < ActionController::TestCase
@request.env["action_dispatch.key_generator"] = ActiveSupport::KeyGenerator.new(SALT, iterations: 2)
@request.env["action_dispatch.signed_cookie_salt"] =
- @request.env["action_dispatch.encrypted_cookie_salt"] =
- @request.env["action_dispatch.encrypted_signed_cookie_salt"] = SALT
+ @request.env["action_dispatch.authenticated_encrypted_cookie_salt"] = SALT
@request.host = "www.nextangle.com"
end
@@ -531,9 +530,7 @@ class CookiesTest < ActionController::TestCase
get :set_encrypted_cookie
cookies = @controller.send :cookies
assert_not_equal "bar", cookies[:foo]
- assert_raise TypeError do
- cookies.signed[:foo]
- end
+ assert_nil cookies.signed[:foo]
assert_equal "bar", cookies.encrypted[:foo]
end
@@ -542,9 +539,7 @@ class CookiesTest < ActionController::TestCase
get :set_encrypted_cookie
cookies = @controller.send :cookies
assert_not_equal "bar", cookies[:foo]
- assert_raises TypeError do
- cookies.signed[:foo]
- end
+ assert_nil cookies.signed[:foo]
assert_equal "bar", cookies.encrypted[:foo]
end
@@ -553,9 +548,7 @@ class CookiesTest < ActionController::TestCase
get :set_encrypted_cookie
cookies = @controller.send :cookies
assert_not_equal "bar", cookies[:foo]
- assert_raises ::JSON::ParserError do
- cookies.signed[:foo]
- end
+ assert_nil cookies.signed[:foo]
assert_equal "bar", cookies.encrypted[:foo]
end
@@ -564,9 +557,7 @@ class CookiesTest < ActionController::TestCase
get :set_wrapped_encrypted_cookie
cookies = @controller.send :cookies
assert_not_equal "wrapped: bar", cookies[:foo]
- assert_raises ::JSON::ParserError do
- cookies.signed[:foo]
- end
+ assert_nil cookies.signed[:foo]
assert_equal "wrapped: bar", cookies.encrypted[:foo]
end
@@ -577,38 +568,16 @@ class CookiesTest < ActionController::TestCase
assert_equal "bar was dumped and loaded", cookies.encrypted[:foo]
end
- def test_encrypted_cookie_using_custom_digest
- @request.env["action_dispatch.cookies_digest"] = "SHA256"
- get :set_encrypted_cookie
- cookies = @controller.send :cookies
- assert_not_equal "bar", cookies[:foo]
- assert_equal "bar", cookies.encrypted[:foo]
-
- sign_secret = @request.env["action_dispatch.key_generator"].generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
-
- sha1_verifier = ActiveSupport::MessageVerifier.new(sign_secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer, digest: "SHA1")
- sha256_verifier = ActiveSupport::MessageVerifier.new(sign_secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer, digest: "SHA256")
-
- assert_raises(ActiveSupport::MessageVerifier::InvalidSignature) do
- sha1_verifier.verify(cookies[:foo])
- end
-
- assert_nothing_raised do
- sha256_verifier.verify(cookies[:foo])
- end
- end
-
def test_encrypted_cookie_using_hybrid_serializer_can_migrate_marshal_dumped_value_to_json
@request.env["action_dispatch.cookies_serializer"] = :hybrid
- key_generator = @request.env["action_dispatch.key_generator"]
- encrypted_cookie_salt = @request.env["action_dispatch.encrypted_cookie_salt"]
- encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
- secret = key_generator.generate_key(encrypted_cookie_salt)
- sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
+ cipher = "aes-256-gcm"
+ salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ secret = @request.env["action_dispatch.key_generator"].generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len(cipher)]
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: Marshal)
- marshal_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: Marshal).encrypt_and_sign("bar")
- @request.headers["Cookie"] = "foo=#{marshal_value}"
+ marshal_value = encryptor.encrypt_and_sign("bar")
+ @request.headers["Cookie"] = "foo=#{::Rack::Utils.escape marshal_value}"
get :get_encrypted_cookie
@@ -616,40 +585,28 @@ class CookiesTest < ActionController::TestCase
assert_not_equal "bar", cookies[:foo]
assert_equal "bar", cookies.encrypted[:foo]
- encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
- assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
+ json_encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: JSON)
+ assert_not_nil @response.cookies["foo"]
+ assert_equal "bar", json_encryptor.decrypt_and_verify(@response.cookies["foo"])
end
def test_encrypted_cookie_using_hybrid_serializer_can_read_from_json_dumped_value
@request.env["action_dispatch.cookies_serializer"] = :hybrid
- key_generator = @request.env["action_dispatch.key_generator"]
- encrypted_cookie_salt = @request.env["action_dispatch.encrypted_cookie_salt"]
- encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
- secret = key_generator.generate_key(encrypted_cookie_salt)
- sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
- json_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON).encrypt_and_sign("bar")
- @request.headers["Cookie"] = "foo=#{json_value}"
-
- get :get_encrypted_cookie
+ cipher = "aes-256-gcm"
+ salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ secret = @request.env["action_dispatch.key_generator"].generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len(cipher)]
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: JSON)
- cookies = @controller.send :cookies
- assert_not_equal "bar", cookies[:foo]
- assert_equal "bar", cookies.encrypted[:foo]
-
- assert_nil @response.cookies["foo"]
- end
-
- def test_compat_encrypted_cookie_using_64_byte_key
- # Cookie generated with 64 bytes secret
- message = ["566d4e75536d686e633246564e6b493062557079626c566d51574d30515430394c53315665564a694e4563786555744f57537454576b396a5a31566a626e52525054303d2d2d34663234333330623130623261306163363562316266323335396164666364613564643134623131"].pack("H*")
- @request.headers["Cookie"] = "foo=#{message}"
+ json_value = encryptor.encrypt_and_sign("bar")
+ @request.headers["Cookie"] = "foo=#{::Rack::Utils.escape json_value}"
get :get_encrypted_cookie
cookies = @controller.send :cookies
assert_not_equal "bar", cookies[:foo]
assert_equal "bar", cookies.encrypted[:foo]
+
assert_nil @response.cookies["foo"]
end
@@ -813,10 +770,10 @@ class CookiesTest < ActionController::TestCase
assert_equal "bar", @controller.send(:cookies).encrypted[:foo]
- key_generator = @request.env["action_dispatch.key_generator"]
- secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
- sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
- encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret)
+ cipher = "aes-256-gcm"
+ salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ secret = @request.env["action_dispatch.key_generator"].generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len(cipher)]
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: Marshal)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
@@ -842,8 +799,6 @@ class CookiesTest < ActionController::TestCase
@request.env["action_dispatch.cookies_serializer"] = :json
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
- @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
- @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate("bar")
@@ -852,10 +807,10 @@ class CookiesTest < ActionController::TestCase
assert_equal "bar", @controller.send(:cookies).encrypted[:foo]
- key_generator = @request.env["action_dispatch.key_generator"]
- secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
- sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
- encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
+ cipher = "aes-256-gcm"
+ salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ secret = @request.env["action_dispatch.key_generator"].generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len(cipher)]
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: JSON)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
@@ -881,8 +836,6 @@ class CookiesTest < ActionController::TestCase
@request.env["action_dispatch.cookies_serializer"] = :hybrid
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
- @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
- @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33", serializer: JSON).generate("bar")
@@ -891,10 +844,10 @@ class CookiesTest < ActionController::TestCase
assert_equal "bar", @controller.send(:cookies).encrypted[:foo]
- key_generator = @request.env["action_dispatch.key_generator"]
- secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
- sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
- encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
+ cipher = "aes-256-gcm"
+ salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ secret = @request.env["action_dispatch.key_generator"].generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len(cipher)]
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: JSON)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
@@ -920,8 +873,6 @@ class CookiesTest < ActionController::TestCase
@request.env["action_dispatch.cookies_serializer"] = :hybrid
@request.env["action_dispatch.secret_token"] = "b3c631c314c0bbca50c1b2843150fe33"
@request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
- @request.env["action_dispatch.encrypted_cookie_salt"] = "4433796b79d99a7735553e316522acee"
- @request.env["action_dispatch.encrypted_signed_cookie_salt"] = "00646eb40062e1b1deff205a27cd30f9"
legacy_value = ActiveSupport::MessageVerifier.new("b3c631c314c0bbca50c1b2843150fe33").generate("bar")
@@ -930,10 +881,10 @@ class CookiesTest < ActionController::TestCase
assert_equal "bar", @controller.send(:cookies).encrypted[:foo]
- key_generator = @request.env["action_dispatch.key_generator"]
- secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
- sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
- encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
+ cipher = "aes-256-gcm"
+ salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ secret = @request.env["action_dispatch.key_generator"].generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len(cipher)]
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: JSON)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
@@ -959,6 +910,89 @@ class CookiesTest < ActionController::TestCase
assert_nil @response.cookies["foo"]
end
+ def test_legacy_hmac_aes_cbc_encrypted_marshal_cookie_is_upgraded_to_authenticated_encrypted_cookie
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+
+ @request.env["action_dispatch.encrypted_cookie_salt"] =
+ @request.env["action_dispatch.encrypted_signed_cookie_salt"] = SALT
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ encrypted_cookie_salt = @request.env["action_dispatch.encrypted_cookie_salt"]
+ encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
+ secret = key_generator.generate_key(encrypted_cookie_salt)
+ sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
+ marshal_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: Marshal).encrypt_and_sign("bar")
+
+ @request.headers["Cookie"] = "foo=#{marshal_value}"
+
+ get :get_encrypted_cookie
+
+ cookies = @controller.send :cookies
+ assert_not_equal "bar", cookies[:foo]
+ assert_equal "bar", cookies.encrypted[:foo]
+
+ aead_cipher = "aes-256-gcm"
+ aead_salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ aead_secret = key_generator.generate_key(aead_salt)[0, ActiveSupport::MessageEncryptor.key_len(aead_cipher)]
+ aead_encryptor = ActiveSupport::MessageEncryptor.new(aead_secret, cipher: aead_cipher, serializer: Marshal)
+
+ assert_equal "bar", aead_encryptor.decrypt_and_verify(@response.cookies["foo"])
+ end
+
+ def test_legacy_hmac_aes_cbc_encrypted_json_cookie_is_upgraded_to_authenticated_encrypted_cookie
+ @request.env["action_dispatch.cookies_serializer"] = :json
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+
+ @request.env["action_dispatch.encrypted_cookie_salt"] =
+ @request.env["action_dispatch.encrypted_signed_cookie_salt"] = SALT
+
+ key_generator = @request.env["action_dispatch.key_generator"]
+ encrypted_cookie_salt = @request.env["action_dispatch.encrypted_cookie_salt"]
+ encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
+ secret = key_generator.generate_key(encrypted_cookie_salt)
+ sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
+ marshal_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON).encrypt_and_sign("bar")
+
+ @request.headers["Cookie"] = "foo=#{marshal_value}"
+
+ get :get_encrypted_cookie
+
+ cookies = @controller.send :cookies
+ assert_not_equal "bar", cookies[:foo]
+ assert_equal "bar", cookies.encrypted[:foo]
+
+ aead_cipher = "aes-256-gcm"
+ aead_salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ aead_secret = key_generator.generate_key(aead_salt)[0, ActiveSupport::MessageEncryptor.key_len(aead_cipher)]
+ aead_encryptor = ActiveSupport::MessageEncryptor.new(aead_secret, cipher: aead_cipher, serializer: JSON)
+
+ assert_equal "bar", aead_encryptor.decrypt_and_verify(@response.cookies["foo"])
+ end
+
+ def test_legacy_hmac_aes_cbc_encrypted_cookie_using_64_byte_key_is_upgraded_to_authenticated_encrypted_cookie
+ @request.env["action_dispatch.secret_key_base"] = "c3b95688f35581fad38df788add315ff"
+
+ @request.env["action_dispatch.encrypted_cookie_salt"] =
+ @request.env["action_dispatch.encrypted_signed_cookie_salt"] = SALT
+
+ # Cookie generated with 64 bytes secret
+ message = ["566d4e75536d686e633246564e6b493062557079626c566d51574d30515430394c53315665564a694e4563786555744f57537454576b396a5a31566a626e52525054303d2d2d34663234333330623130623261306163363562316266323335396164666364613564643134623131"].pack("H*")
+ @request.headers["Cookie"] = "foo=#{message}"
+
+ get :get_encrypted_cookie
+
+ cookies = @controller.send :cookies
+ assert_not_equal "bar", cookies[:foo]
+ assert_equal "bar", cookies.encrypted[:foo]
+ cipher = "aes-256-gcm"
+
+ salt = @request.env["action_dispatch.authenticated_encrypted_cookie_salt"]
+ secret = @request.env["action_dispatch.key_generator"].generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len(cipher)]
+ encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: cipher, serializer: Marshal)
+
+ assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
+ end
+
def test_cookie_with_all_domain_option
get :set_cookie_with_domain
assert_response :success
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index ea477e8908..60acba0616 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "abstract_unit"
class DebugExceptionsTest < ActionDispatch::IntegrationTest
@@ -344,7 +346,7 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
})
assert_response 500
- assert_includes(body, CGI.escapeHTML(PP.pp(params, "", 200)))
+ assert_includes(body, CGI.escapeHTML(PP.pp(params, "".dup, 200)))
end
test "sets the HTTP charset parameter" do
diff --git a/actionpack/test/dispatch/prefix_generation_test.rb b/actionpack/test/dispatch/prefix_generation_test.rb
index bb2fc53add..85ea04356a 100644
--- a/actionpack/test/dispatch/prefix_generation_test.rb
+++ b/actionpack/test/dispatch/prefix_generation_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "abstract_unit"
require "rack/test"
require "rails/engine"
@@ -11,7 +13,7 @@ module TestGenerationPrefix
end
def self.model_name
- klass = "Post"
+ klass = "Post".dup
def klass.name; self end
ActiveModel::Name.new(klass)
@@ -22,8 +24,6 @@ module TestGenerationPrefix
end
class WithMountedEngine < ActionDispatch::IntegrationTest
- include Rack::Test::Methods
-
class BlogEngine < Rails::Engine
routes.draw do
get "/posts/:id", to: "inside_engine_generating#show", as: :post
@@ -153,114 +153,114 @@ module TestGenerationPrefix
# Inside Engine
test "[ENGINE] generating engine's url use SCRIPT_NAME from request" do
get "/pure-awesomeness/blog/posts/1"
- assert_equal "/pure-awesomeness/blog/posts/1", last_response.body
+ assert_equal "/pure-awesomeness/blog/posts/1", response.body
end
test "[ENGINE] generating application's url never uses SCRIPT_NAME from request" do
get "/pure-awesomeness/blog/url_to_application"
- assert_equal "/generate", last_response.body
+ assert_equal "/generate", response.body
end
test "[ENGINE] generating engine's url with polymorphic path" do
get "/pure-awesomeness/blog/polymorphic_path_for_engine"
- assert_equal "/pure-awesomeness/blog/posts/1", last_response.body
+ assert_equal "/pure-awesomeness/blog/posts/1", response.body
end
test "[ENGINE] url_helpers from engine have higher priority than application's url_helpers" do
get "/awesome/blog/conflicting_url"
- assert_equal "engine", last_response.body
+ assert_equal "engine", response.body
end
test "[ENGINE] relative path root uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_path_root"
- verify_redirect "http://example.org/awesome/blog"
+ verify_redirect "http://www.example.com/awesome/blog"
end
test "[ENGINE] relative path redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_path_redirect"
- verify_redirect "http://example.org/awesome/blog/foo"
+ verify_redirect "http://www.example.com/awesome/blog/foo"
end
test "[ENGINE] relative option root uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_option_root"
- verify_redirect "http://example.org/awesome/blog"
+ verify_redirect "http://www.example.com/awesome/blog"
end
test "[ENGINE] relative option redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_option_redirect"
- verify_redirect "http://example.org/awesome/blog/foo"
+ verify_redirect "http://www.example.com/awesome/blog/foo"
end
test "[ENGINE] relative custom root uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_custom_root"
- verify_redirect "http://example.org/awesome/blog"
+ verify_redirect "http://www.example.com/awesome/blog"
end
test "[ENGINE] relative custom redirect uses SCRIPT_NAME from request" do
get "/awesome/blog/relative_custom_redirect"
- verify_redirect "http://example.org/awesome/blog/foo"
+ verify_redirect "http://www.example.com/awesome/blog/foo"
end
test "[ENGINE] absolute path root doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_path_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute path redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_path_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute option root doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_option_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute option redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_option_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute custom root doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_custom_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute custom redirect doesn't use SCRIPT_NAME from request" do
get "/awesome/blog/absolute_custom_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
# Inside Application
test "[APP] generating engine's route includes prefix" do
get "/generate"
- assert_equal "/awesome/blog/posts/1", last_response.body
+ assert_equal "/awesome/blog/posts/1", response.body
end
test "[APP] generating engine's route includes default_url_options[:script_name]" do
RailsApplication.routes.default_url_options = { script_name: "/something" }
get "/generate"
- assert_equal "/something/awesome/blog/posts/1", last_response.body
+ assert_equal "/something/awesome/blog/posts/1", response.body
end
test "[APP] generating engine's url with polymorphic path" do
get "/polymorphic_path_for_engine"
- assert_equal "/awesome/blog/posts/1", last_response.body
+ assert_equal "/awesome/blog/posts/1", response.body
end
test "polymorphic_path_for_app" do
get "/polymorphic_path_for_app"
- assert_equal "/posts/1", last_response.body
+ assert_equal "/posts/1", response.body
end
test "[APP] generating engine's url with url_for(@post)" do
get "/polymorphic_with_url_for"
- assert_equal "http://example.org/awesome/blog/posts/1", last_response.body
+ assert_equal "http://www.example.com/awesome/blog/posts/1", response.body
end
test "[APP] instance variable with same name as engine" do
get "/ivar_usage"
- assert_equal "/awesome/blog/posts/1", last_response.body
+ assert_equal "/awesome/blog/posts/1", response.body
end
# Inside any Object
@@ -322,9 +322,9 @@ module TestGenerationPrefix
private
def verify_redirect(url, status = 301)
- assert_equal status, last_response.status
- assert_equal url, last_response.headers["Location"]
- assert_equal expected_redirect_body(url), last_response.body
+ assert_equal status, response.status
+ assert_equal url, response.headers["Location"]
+ assert_equal expected_redirect_body(url), response.body
end
def expected_redirect_body(url)
@@ -333,8 +333,6 @@ module TestGenerationPrefix
end
class EngineMountedAtRoot < ActionDispatch::IntegrationTest
- include Rack::Test::Methods
-
class BlogEngine
def self.routes
@routes ||= begin
@@ -388,74 +386,74 @@ module TestGenerationPrefix
test "generating path inside engine" do
get "/posts/1"
- assert_equal "/posts/1", last_response.body
+ assert_equal "/posts/1", response.body
end
test "[ENGINE] relative path root uses SCRIPT_NAME from request" do
get "/relative_path_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] relative path redirect uses SCRIPT_NAME from request" do
get "/relative_path_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] relative option root uses SCRIPT_NAME from request" do
get "/relative_option_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] relative option redirect uses SCRIPT_NAME from request" do
get "/relative_option_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] relative custom root uses SCRIPT_NAME from request" do
get "/relative_custom_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] relative custom redirect uses SCRIPT_NAME from request" do
get "/relative_custom_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute path root doesn't use SCRIPT_NAME from request" do
get "/absolute_path_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute path redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_path_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute option root doesn't use SCRIPT_NAME from request" do
get "/absolute_option_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute option redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_option_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
test "[ENGINE] absolute custom root doesn't use SCRIPT_NAME from request" do
get "/absolute_custom_root"
- verify_redirect "http://example.org/"
+ verify_redirect "http://www.example.com/"
end
test "[ENGINE] absolute custom redirect doesn't use SCRIPT_NAME from request" do
get "/absolute_custom_redirect"
- verify_redirect "http://example.org/foo"
+ verify_redirect "http://www.example.com/foo"
end
private
def verify_redirect(url, status = 301)
- assert_equal status, last_response.status
- assert_equal url, last_response.headers["Location"]
- assert_equal expected_redirect_body(url), last_response.body
+ assert_equal status, response.status
+ assert_equal url, response.headers["Location"]
+ assert_equal expected_redirect_body(url), response.body
end
def expected_redirect_body(url)
diff --git a/actionpack/test/dispatch/reloader_test.rb b/actionpack/test/dispatch/reloader_test.rb
index db68549b84..9eb78fe059 100644
--- a/actionpack/test/dispatch/reloader_test.rb
+++ b/actionpack/test/dispatch/reloader_test.rb
@@ -1,32 +1,11 @@
require "abstract_unit"
class ReloaderTest < ActiveSupport::TestCase
- Reloader = ActionDispatch::Reloader
-
teardown do
ActiveSupport::Reloader.reset_callbacks :prepare
ActiveSupport::Reloader.reset_callbacks :complete
end
- def test_prepare_callbacks
- a = b = c = nil
- assert_deprecated do
- Reloader.to_prepare { |*args| a = b = c = 1 }
- Reloader.to_prepare { |*args| b = c = 2 }
- Reloader.to_prepare { |*args| c = 3 }
- end
-
- # Ensure to_prepare callbacks are not run when defined
- assert_nil a || b || c
-
- # Run callbacks
- call_and_return_body
-
- assert_equal 1, a
- assert_equal 2, b
- assert_equal 3, c
- end
-
class MyBody < Array
def initialize(&block)
@on_close = block
@@ -45,6 +24,23 @@ class ReloaderTest < ActiveSupport::TestCase
end
end
+ def test_prepare_callbacks
+ a = b = c = nil
+ reloader.to_prepare { |*args| a = b = c = 1 }
+ reloader.to_prepare { |*args| b = c = 2 }
+ reloader.to_prepare { |*args| c = 3 }
+
+ # Ensure to_prepare callbacks are not run when defined
+ assert_nil a || b || c
+
+ # Run callbacks
+ call_and_return_body
+
+ assert_equal 1, a
+ assert_equal 2, b
+ assert_equal 3, c
+ end
+
def test_returned_body_object_always_responds_to_close
body = call_and_return_body
assert_respond_to body, :close
@@ -62,15 +58,12 @@ class ReloaderTest < ActiveSupport::TestCase
def test_condition_specifies_when_to_reload
i, j = 0, 0, 0, 0
- assert_deprecated do
- Reloader.to_prepare { |*args| i += 1 }
- Reloader.to_cleanup { |*args| j += 1 }
- end
- x = Class.new(ActiveSupport::Reloader)
- x.check = lambda { i < 3 }
+ reloader = reloader(lambda { i < 3 })
+ reloader.to_prepare { |*args| i += 1 }
+ reloader.to_complete { |*args| j += 1 }
- app = Reloader.new(lambda { |env| [200, {}, []] }, x)
+ app = middleware(lambda { |env| [200, {}, []] }, reloader)
5.times do
resp = app.call({})
resp[2].close
@@ -115,24 +108,20 @@ class ReloaderTest < ActiveSupport::TestCase
assert_respond_to body, :bar
end
- def test_cleanup_callbacks_are_called_when_body_is_closed
- cleaned = false
- assert_deprecated do
- Reloader.to_cleanup { cleaned = true }
- end
+ def test_complete_callbacks_are_called_when_body_is_closed
+ completed = false
+ reloader.to_complete { completed = true }
body = call_and_return_body
- assert !cleaned
+ assert !completed
body.close
- assert cleaned
+ assert completed
end
def test_prepare_callbacks_arent_called_when_body_is_closed
prepared = false
- assert_deprecated do
- Reloader.to_prepare { prepared = true }
- end
+ reloader.to_prepare { prepared = true }
body = call_and_return_body
prepared = false
@@ -141,45 +130,9 @@ class ReloaderTest < ActiveSupport::TestCase
assert !prepared
end
- def test_manual_reloading
- prepared = cleaned = false
- assert_deprecated do
- Reloader.to_prepare { prepared = true }
- Reloader.to_cleanup { cleaned = true }
- end
-
- assert_deprecated do
- Reloader.prepare!
- end
- assert prepared
- assert !cleaned
-
- prepared = cleaned = false
- assert_deprecated do
- Reloader.cleanup!
- end
- assert prepared
- assert cleaned
- end
-
- def test_prepend_prepare_callback
- i = 10
- assert_deprecated do
- Reloader.to_prepare { i += 1 }
- Reloader.to_prepare(prepend: true) { i = 0 }
- end
-
- assert_deprecated do
- Reloader.prepare!
- end
- assert_equal 1, i
- end
-
- def test_cleanup_callbacks_are_called_on_exceptions
- cleaned = false
- assert_deprecated do
- Reloader.to_cleanup { cleaned = true }
- end
+ def test_complete_callbacks_are_called_on_exceptions
+ completed = false
+ reloader.to_complete { completed = true }
begin
call_and_return_body do
@@ -188,16 +141,25 @@ class ReloaderTest < ActiveSupport::TestCase
rescue
end
- assert cleaned
+ assert completed
end
private
def call_and_return_body(&block)
- x = Class.new(ActiveSupport::Reloader)
- x.check = lambda { true }
+ app = middleware(block || proc { [200, {}, "response"] })
+ _, _, body = app.call("rack.input" => StringIO.new(""))
+ body
+ end
+
+ def middleware(inner_app, reloader = reloader())
+ ActionDispatch::Reloader.new(inner_app, reloader)
+ end
- @response ||= "response"
- @reloader ||= Reloader.new(block || proc { [200, {}, @response] }, x)
- @reloader.call("rack.input" => StringIO.new(""))[2]
+ def reloader(check = lambda { true })
+ @reloader ||= begin
+ reloader = Class.new(ActiveSupport::Reloader)
+ reloader.check = check
+ reloader
+ end
end
end
diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
index 01c5ff1429..e7e8c82974 100644
--- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
@@ -21,7 +21,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
end
end
- FIXTURE_PATH = File.dirname(__FILE__) + "/../../fixtures/multipart"
+ FIXTURE_PATH = File.expand_path("../../fixtures/multipart", __dir__)
def teardown
TestController.last_request_parameters = nil
diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb
index 311b80ea0a..228135c547 100644
--- a/actionpack/test/dispatch/request/session_test.rb
+++ b/actionpack/test/dispatch/request/session_test.rb
@@ -54,6 +54,11 @@ module ActionDispatch
assert_equal %w[rails adequate], s.keys
end
+ def test_keys_with_deferred_loading
+ s = Session.create(store_with_data, req, {})
+ assert_equal %w[sample_key], s.keys
+ end
+
def test_values
s = Session.create(store, req, {})
s["rails"] = "ftw"
@@ -61,6 +66,11 @@ module ActionDispatch
assert_equal %w[ftw awesome], s.values
end
+ def test_values_with_deferred_loading
+ s = Session.create(store_with_data, req, {})
+ assert_equal %w[sample_value], s.values
+ end
+
def test_clear
s = Session.create(store, req, {})
s["rails"] = "ftw"
@@ -113,6 +123,14 @@ module ActionDispatch
def delete_session(env, id, options); 123; end
}.new
end
+
+ def store_with_data
+ Class.new {
+ def load_session(env); [1, { "sample_key" => "sample_value" }]; end
+ def session_exists?(env); true; end
+ def delete_session(env, id, options); 123; end
+ }.new
+ end
end
class SessionIntegrationTest < ActionDispatch::IntegrationTest
diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
index 1169bf0cdb..6721a388c1 100644
--- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
@@ -107,7 +107,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest
query = [
"customers[boston][first][name]=David",
"something_else=blah",
- "logo=#{File.expand_path(__FILE__)}"
+ "logo=#{__FILE__}"
].join("&")
expected = {
"customers" => {
@@ -118,7 +118,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest
}
},
"something_else" => "blah",
- "logo" => File.expand_path(__FILE__),
+ "logo" => __FILE__,
}
assert_parses expected, query
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index e11b93b4f0..899b27b962 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -110,8 +110,8 @@ class RequestIP < BaseRequestTest
request.remote_ip
}
assert_match(/IP spoofing attack/, e.message)
- assert_match(/HTTP_X_FORWARDED_FOR="1.1.1.1"/, e.message)
- assert_match(/HTTP_CLIENT_IP="2.2.2.2"/, e.message)
+ assert_match(/HTTP_X_FORWARDED_FOR="1\.1\.1\.1"/, e.message)
+ assert_match(/HTTP_CLIENT_IP="2\.2\.2\.2"/, e.message)
end
test "remote ip with spoof detection disabled" do
@@ -760,8 +760,8 @@ class RequestMethod < BaseRequestTest
end
test "post uneffected by local inflections" do
- existing_acrnoyms = ActiveSupport::Inflector.inflections.acronyms.dup
- existing_acrnoym_regex = ActiveSupport::Inflector.inflections.acronym_regex.dup
+ existing_acronyms = ActiveSupport::Inflector.inflections.acronyms.dup
+ existing_acronym_regex = ActiveSupport::Inflector.inflections.acronym_regex.dup
begin
ActiveSupport::Inflector.inflections do |inflect|
inflect.acronym "POS"
@@ -774,8 +774,8 @@ class RequestMethod < BaseRequestTest
ensure
# Reset original acronym set
ActiveSupport::Inflector.inflections do |inflect|
- inflect.send(:instance_variable_set, "@acronyms", existing_acrnoyms)
- inflect.send(:instance_variable_set, "@acronym_regex", existing_acrnoym_regex)
+ inflect.send(:instance_variable_set, "@acronyms", existing_acronyms)
+ inflect.send(:instance_variable_set, "@acronym_regex", existing_acronym_regex)
end
end
end
@@ -1098,6 +1098,19 @@ class RequestParameterFilter < BaseRequestTest
end
end
+ test "parameter filter should maintain hash with indifferent access" do
+ test_hashes = [
+ [{ "foo" => "bar" }.with_indifferent_access, ["blah"]],
+ [{ "foo" => "bar" }.with_indifferent_access, []]
+ ]
+
+ test_hashes.each do |before_filter, filter_words|
+ parameter_filter = ActionDispatch::Http::ParameterFilter.new(filter_words)
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess,
+ parameter_filter.filter(before_filter)
+ end
+ end
+
test "filtered_parameters returns params filtered" do
request = stub_request(
"action_dispatch.request.parameters" => {
diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb
new file mode 100644
index 0000000000..cbbed66056
--- /dev/null
+++ b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb
@@ -0,0 +1,331 @@
+require "abstract_unit"
+
+class TestCustomUrlHelpers < ActionDispatch::IntegrationTest
+ class Linkable
+ attr_reader :id
+
+ def self.name
+ super.demodulize
+ end
+
+ def initialize(id)
+ @id = id
+ end
+
+ def linkable_type
+ self.class.name.underscore
+ end
+ end
+
+ class Category < Linkable; end
+ class Collection < Linkable; end
+ class Product < Linkable; end
+ class Manufacturer < Linkable; end
+
+ class Model
+ extend ActiveModel::Naming
+ include ActiveModel::Conversion
+
+ attr_reader :id
+
+ def initialize(id = nil)
+ @id = id
+ end
+
+ remove_method :model_name
+ def model_name
+ @_model_name ||= ActiveModel::Name.new(self.class, nil, self.class.name.demodulize)
+ end
+
+ def persisted?
+ false
+ end
+ end
+
+ class Basket < Model; end
+ class User < Model; end
+ class Video < Model; end
+
+ class Article
+ attr_reader :id
+
+ def self.name
+ "Article"
+ end
+
+ def initialize(id)
+ @id = id
+ end
+ end
+
+ class Page
+ attr_reader :id
+
+ def self.name
+ super.demodulize
+ end
+
+ def initialize(id)
+ @id = id
+ end
+ end
+
+ class CategoryPage < Page; end
+ class ProductPage < Page; end
+
+ Routes = ActionDispatch::Routing::RouteSet.new
+ Routes.draw do
+ default_url_options host: "www.example.com"
+
+ root to: "pages#index"
+ get "/basket", to: "basket#show", as: :basket
+ get "/posts/:id", to: "posts#show", as: :post
+ get "/profile", to: "users#profile", as: :profile
+ get "/media/:id", to: "media#show", as: :media
+ get "/pages/:id", to: "pages#show", as: :page
+
+ resources :categories, :collections, :products, :manufacturers
+
+ namespace :admin do
+ get "/dashboard", to: "dashboard#index"
+ end
+
+ direct(:website) { "http://www.rubyonrails.org" }
+ direct("string") { "http://www.rubyonrails.org" }
+ direct(:helper) { basket_url }
+ direct(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] }
+ direct(:nested) { |linkable| route_for(:linkable, linkable) }
+ direct(:params) { |params| params }
+ direct(:symbol) { :basket }
+ direct(:hash) { { controller: "basket", action: "show" } }
+ direct(:array) { [:admin, :dashboard] }
+ direct(:options) { |options| [:products, options] }
+ direct(:defaults, size: 10) { |options| [:products, options] }
+
+ direct(:browse, page: 1, size: 10) do |options|
+ [:products, options.merge(params.permit(:page, :size).to_h.symbolize_keys)]
+ end
+
+ resolve("Article") { |article| [:post, { id: article.id }] }
+ resolve("Basket") { |basket| [:basket] }
+ resolve("Manufacturer") { |manufacturer| route_for(:linkable, manufacturer) }
+ resolve("User", anchor: "details") { |user, options| [:profile, options] }
+ resolve("Video") { |video| [:media, { id: video.id }] }
+ resolve(%w[Page CategoryPage ProductPage]) { |page| [:page, { id: page.id }] }
+ end
+
+ APP = build_app Routes
+
+ def app
+ APP
+ end
+
+ include Routes.url_helpers
+
+ def setup
+ @category = Category.new("1")
+ @collection = Collection.new("2")
+ @product = Product.new("3")
+ @manufacturer = Manufacturer.new("apple")
+ @basket = Basket.new
+ @user = User.new
+ @video = Video.new("4")
+ @article = Article.new("5")
+ @page = Page.new("6")
+ @category_page = CategoryPage.new("7")
+ @product_page = ProductPage.new("8")
+ @path_params = { "controller" => "pages", "action" => "index" }
+ @unsafe_params = ActionController::Parameters.new(@path_params)
+ @safe_params = ActionController::Parameters.new(@path_params).permit(:controller, :action)
+ end
+
+ def params
+ ActionController::Parameters.new(page: 2, size: 25)
+ end
+
+ def test_direct_paths
+ assert_equal "/", website_path
+ assert_equal "/", Routes.url_helpers.website_path
+
+ assert_equal "/", string_path
+ assert_equal "/", Routes.url_helpers.string_path
+
+ assert_equal "/basket", helper_path
+ assert_equal "/basket", Routes.url_helpers.helper_path
+
+ assert_equal "/categories/1", linkable_path(@category)
+ assert_equal "/categories/1", Routes.url_helpers.linkable_path(@category)
+ assert_equal "/collections/2", linkable_path(@collection)
+ assert_equal "/collections/2", Routes.url_helpers.linkable_path(@collection)
+ assert_equal "/products/3", linkable_path(@product)
+ assert_equal "/products/3", Routes.url_helpers.linkable_path(@product)
+
+ assert_equal "/categories/1", nested_path(@category)
+ assert_equal "/categories/1", Routes.url_helpers.nested_path(@category)
+
+ assert_equal "/", params_path(@safe_params)
+ assert_equal "/", Routes.url_helpers.params_path(@safe_params)
+ assert_raises(ActionController::UnfilteredParameters) { params_path(@unsafe_params) }
+ assert_raises(ActionController::UnfilteredParameters) { Routes.url_helpers.params_path(@unsafe_params) }
+
+ assert_equal "/basket", symbol_path
+ assert_equal "/basket", Routes.url_helpers.symbol_path
+ assert_equal "/basket", hash_path
+ assert_equal "/basket", Routes.url_helpers.hash_path
+ assert_equal "/admin/dashboard", array_path
+ assert_equal "/admin/dashboard", Routes.url_helpers.array_path
+
+ assert_equal "/products?page=2", options_path(page: 2)
+ assert_equal "/products?page=2", Routes.url_helpers.options_path(page: 2)
+ assert_equal "/products?size=10", defaults_path
+ assert_equal "/products?size=10", Routes.url_helpers.defaults_path
+ assert_equal "/products?size=20", defaults_path(size: 20)
+ assert_equal "/products?size=20", Routes.url_helpers.defaults_path(size: 20)
+
+ assert_equal "/products?page=2&size=25", browse_path
+ assert_raises(NameError) { Routes.url_helpers.browse_path }
+ end
+
+ def test_direct_urls
+ assert_equal "http://www.rubyonrails.org", website_url
+ assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_url
+
+ assert_equal "http://www.rubyonrails.org", string_url
+ assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_url
+
+ assert_equal "http://www.example.com/basket", helper_url
+ assert_equal "http://www.example.com/basket", Routes.url_helpers.helper_url
+
+ assert_equal "http://www.example.com/categories/1", linkable_url(@category)
+ assert_equal "http://www.example.com/categories/1", Routes.url_helpers.linkable_url(@category)
+ assert_equal "http://www.example.com/collections/2", linkable_url(@collection)
+ assert_equal "http://www.example.com/collections/2", Routes.url_helpers.linkable_url(@collection)
+ assert_equal "http://www.example.com/products/3", linkable_url(@product)
+ assert_equal "http://www.example.com/products/3", Routes.url_helpers.linkable_url(@product)
+
+ assert_equal "http://www.example.com/categories/1", nested_url(@category)
+ assert_equal "http://www.example.com/categories/1", Routes.url_helpers.nested_url(@category)
+
+ assert_equal "http://www.example.com/", params_url(@safe_params)
+ assert_equal "http://www.example.com/", Routes.url_helpers.params_url(@safe_params)
+ assert_raises(ActionController::UnfilteredParameters) { params_url(@unsafe_params) }
+ assert_raises(ActionController::UnfilteredParameters) { Routes.url_helpers.params_url(@unsafe_params) }
+
+ assert_equal "http://www.example.com/basket", symbol_url
+ assert_equal "http://www.example.com/basket", Routes.url_helpers.symbol_url
+ assert_equal "http://www.example.com/basket", hash_url
+ assert_equal "http://www.example.com/basket", Routes.url_helpers.hash_url
+ assert_equal "http://www.example.com/admin/dashboard", array_url
+ assert_equal "http://www.example.com/admin/dashboard", Routes.url_helpers.array_url
+
+ assert_equal "http://www.example.com/products?page=2", options_url(page: 2)
+ assert_equal "http://www.example.com/products?page=2", Routes.url_helpers.options_url(page: 2)
+ assert_equal "http://www.example.com/products?size=10", defaults_url
+ assert_equal "http://www.example.com/products?size=10", Routes.url_helpers.defaults_url
+ assert_equal "http://www.example.com/products?size=20", defaults_url(size: 20)
+ assert_equal "http://www.example.com/products?size=20", Routes.url_helpers.defaults_url(size: 20)
+
+ assert_equal "http://www.example.com/products?page=2&size=25", browse_url
+ assert_raises(NameError) { Routes.url_helpers.browse_url }
+ end
+
+ def test_resolve_paths
+ assert_equal "/basket", polymorphic_path(@basket)
+ assert_equal "/basket", Routes.url_helpers.polymorphic_path(@basket)
+
+ assert_equal "/profile#details", polymorphic_path(@user)
+ assert_equal "/profile#details", Routes.url_helpers.polymorphic_path(@user)
+
+ assert_equal "/profile#password", polymorphic_path(@user, anchor: "password")
+ assert_equal "/profile#password", Routes.url_helpers.polymorphic_path(@user, anchor: "password")
+
+ assert_equal "/media/4", polymorphic_path(@video)
+ assert_equal "/media/4", Routes.url_helpers.polymorphic_path(@video)
+ assert_equal "/media/4", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @video)
+
+ assert_equal "/posts/5", polymorphic_path(@article)
+ assert_equal "/posts/5", Routes.url_helpers.polymorphic_path(@article)
+ assert_equal "/posts/5", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @article)
+
+ assert_equal "/pages/6", polymorphic_path(@page)
+ assert_equal "/pages/6", Routes.url_helpers.polymorphic_path(@page)
+ assert_equal "/pages/6", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @page)
+
+ assert_equal "/pages/7", polymorphic_path(@category_page)
+ assert_equal "/pages/7", Routes.url_helpers.polymorphic_path(@category_page)
+ assert_equal "/pages/7", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @category_page)
+
+ assert_equal "/pages/8", polymorphic_path(@product_page)
+ assert_equal "/pages/8", Routes.url_helpers.polymorphic_path(@product_page)
+ assert_equal "/pages/8", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @product_page)
+
+ assert_equal "/manufacturers/apple", polymorphic_path(@manufacturer)
+ assert_equal "/manufacturers/apple", Routes.url_helpers.polymorphic_path(@manufacturer)
+ end
+
+ def test_resolve_urls
+ assert_equal "http://www.example.com/basket", polymorphic_url(@basket)
+ assert_equal "http://www.example.com/basket", Routes.url_helpers.polymorphic_url(@basket)
+ assert_equal "http://www.example.com/basket", polymorphic_url(@basket)
+ assert_equal "http://www.example.com/basket", Routes.url_helpers.polymorphic_url(@basket)
+
+ assert_equal "http://www.example.com/profile#details", polymorphic_url(@user)
+ assert_equal "http://www.example.com/profile#details", Routes.url_helpers.polymorphic_url(@user)
+
+ assert_equal "http://www.example.com/profile#password", polymorphic_url(@user, anchor: "password")
+ assert_equal "http://www.example.com/profile#password", Routes.url_helpers.polymorphic_url(@user, anchor: "password")
+
+ assert_equal "http://www.example.com/media/4", polymorphic_url(@video)
+ assert_equal "http://www.example.com/media/4", Routes.url_helpers.polymorphic_url(@video)
+ assert_equal "http://www.example.com/media/4", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @video)
+
+ assert_equal "http://www.example.com/posts/5", polymorphic_url(@article)
+ assert_equal "http://www.example.com/posts/5", Routes.url_helpers.polymorphic_url(@article)
+ assert_equal "http://www.example.com/posts/5", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @article)
+
+ assert_equal "http://www.example.com/pages/6", polymorphic_url(@page)
+ assert_equal "http://www.example.com/pages/6", Routes.url_helpers.polymorphic_url(@page)
+ assert_equal "http://www.example.com/pages/6", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @page)
+
+ assert_equal "http://www.example.com/pages/7", polymorphic_url(@category_page)
+ assert_equal "http://www.example.com/pages/7", Routes.url_helpers.polymorphic_url(@category_page)
+ assert_equal "http://www.example.com/pages/7", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @category_page)
+
+ assert_equal "http://www.example.com/pages/8", polymorphic_url(@product_page)
+ assert_equal "http://www.example.com/pages/8", Routes.url_helpers.polymorphic_url(@product_page)
+ assert_equal "http://www.example.com/pages/8", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @product_page)
+
+ assert_equal "http://www.example.com/manufacturers/apple", polymorphic_url(@manufacturer)
+ assert_equal "http://www.example.com/manufacturers/apple", Routes.url_helpers.polymorphic_url(@manufacturer)
+ end
+
+ def test_defining_direct_inside_a_scope_raises_runtime_error
+ routes = ActionDispatch::Routing::RouteSet.new
+
+ assert_raises RuntimeError do
+ routes.draw do
+ namespace :admin do
+ direct(:rubyonrails) { "http://www.rubyonrails.org" }
+ end
+ end
+ end
+ end
+
+ def test_defining_resolve_inside_a_scope_raises_runtime_error
+ routes = ActionDispatch::Routing::RouteSet.new
+
+ assert_raises RuntimeError do
+ routes.draw do
+ namespace :admin do
+ resolve("User") { "/profile" }
+ end
+ end
+ end
+ end
+
+ def test_defining_direct_url_registers_helper_method
+ assert_equal "http://www.example.com/basket", Routes.url_helpers.symbol_url
+ assert_equal true, Routes.named_routes.route_defined?(:symbol_url), "'symbol_url' named helper not found"
+ assert_equal true, Routes.named_routes.route_defined?(:symbol_path), "'symbol_path' named helper not found"
+ end
+end
diff --git a/actionpack/test/dispatch/routing/route_set_test.rb b/actionpack/test/dispatch/routing/route_set_test.rb
index ace35dda53..d6ecbda092 100644
--- a/actionpack/test/dispatch/routing/route_set_test.rb
+++ b/actionpack/test/dispatch/routing/route_set_test.rb
@@ -138,6 +138,15 @@ module ActionDispatch
assert_equal "/a/users/1", url_helpers.user_path(1, foo: "a")
end
+ test "implicit path components consistently return the same result" do
+ draw do
+ resources :users, to: SimpleApp.new("foo#index")
+ end
+ assert_equal "/users/1.json", url_helpers.user_path(1, :json)
+ assert_equal "/users/1.json", url_helpers.user_path(1, format: :json)
+ assert_equal "/users/1.json", url_helpers.user_path(1, :json)
+ end
+
private
def draw(&block)
@set.draw(&block)
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 53758a4fbc..32cd78e492 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -3633,7 +3633,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
params = ActionController::Parameters.new(id: "1")
- assert_raises ArgumentError do
+ assert_raises ActionController::UnfilteredParameters do
root_path(params)
end
end
@@ -3706,6 +3706,24 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal "/bar", bar_root_path
end
+ def test_nested_routes_under_format_resource
+ draw do
+ resources :formats do
+ resources :items
+ end
+ end
+
+ get "/formats/1/items.json"
+ assert_equal 200, @response.status
+ assert_equal "items#index", @response.body
+ assert_equal "/formats/1/items.json", format_items_path(1, :json)
+
+ get "/formats/1/items/2.json"
+ assert_equal 200, @response.status
+ assert_equal "items#show", @response.body
+ assert_equal "/formats/1/items/2.json", format_item_path(1, 2, :json)
+ end
+
private
def draw(&block)
@@ -4401,7 +4419,7 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
end
end
- test "invalid UTF-8 encoding returns a 400 Bad Request" do
+ test "invalid UTF-8 encoding is treated as ASCII 8BIT encode" do
with_routing do |set|
set.draw do
get "/bar/:id", to: redirect("/foo/show/%{id}")
@@ -4417,19 +4435,19 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest
end
get "/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :not_found
get "/foo/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :not_found
get "/foo/show/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :ok
get "/bar/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :redirect
get "/foobar/%E2%EF%BF%BD%A6"
- assert_response :bad_request
+ assert_response :ok
end
end
end
@@ -4913,3 +4931,113 @@ class TestInternalRoutingParams < ActionDispatch::IntegrationTest
)
end
end
+
+class FlashRedirectTest < ActionDispatch::IntegrationTest
+ SessionKey = "_myapp_session"
+ Generator = ActiveSupport::LegacyKeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33")
+
+ class KeyGeneratorMiddleware
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ env["action_dispatch.key_generator"] ||= Generator
+ @app.call(env)
+ end
+ end
+
+ class FooController < ActionController::Base
+ def bar
+ render plain: (flash[:foo] || "foo")
+ end
+ end
+
+ Routes = ActionDispatch::Routing::RouteSet.new
+ Routes.draw do
+ get "/foo", to: redirect { |params, req| req.flash[:foo] = "bar"; "/bar" }
+ get "/bar", to: "flash_redirect_test/foo#bar"
+ end
+
+ APP = build_app Routes do |middleware|
+ middleware.use KeyGeneratorMiddleware
+ middleware.use ActionDispatch::Session::CookieStore, key: SessionKey
+ middleware.use ActionDispatch::Flash
+ middleware.delete ActionDispatch::ShowExceptions
+ end
+
+ def app
+ APP
+ end
+
+ include Routes.url_helpers
+
+ def test_block_redirect_commits_flash
+ get "/foo", env: { "action_dispatch.key_generator" => Generator }
+ assert_response :redirect
+
+ follow_redirect!
+ assert_equal "bar", response.body
+ end
+end
+
+class TestRecognizePath < ActionDispatch::IntegrationTest
+ class PageConstraint
+ attr_reader :key, :pattern
+
+ def initialize(key, pattern)
+ @key = key
+ @pattern = pattern
+ end
+
+ def matches?(request)
+ request.path_parameters[key] =~ pattern
+ end
+ end
+
+ stub_controllers do |routes|
+ Routes = routes
+ routes.draw do
+ get "/hash/:foo", to: "pages#show", constraints: { foo: /foo/ }
+ get "/hash/:bar", to: "pages#show", constraints: { bar: /bar/ }
+
+ get "/proc/:foo", to: "pages#show", constraints: proc { |r| r.path_parameters[:foo] =~ /foo/ }
+ get "/proc/:bar", to: "pages#show", constraints: proc { |r| r.path_parameters[:bar] =~ /bar/ }
+
+ get "/class/:foo", to: "pages#show", constraints: PageConstraint.new(:foo, /foo/)
+ get "/class/:bar", to: "pages#show", constraints: PageConstraint.new(:bar, /bar/)
+ end
+ end
+
+ APP = build_app Routes
+ def app
+ APP
+ end
+
+ def test_hash_constraints_dont_leak_between_routes
+ expected_params = { controller: "pages", action: "show", bar: "bar" }
+ actual_params = recognize_path("/hash/bar")
+
+ assert_equal expected_params, actual_params
+ end
+
+ def test_proc_constraints_dont_leak_between_routes
+ expected_params = { controller: "pages", action: "show", bar: "bar" }
+ actual_params = recognize_path("/proc/bar")
+
+ assert_equal expected_params, actual_params
+ end
+
+ def test_class_constraints_dont_leak_between_routes
+ expected_params = { controller: "pages", action: "show", bar: "bar" }
+ actual_params = recognize_path("/class/bar")
+
+ assert_equal expected_params, actual_params
+ end
+
+ private
+
+ def recognize_path(*args)
+ Routes.recognize_path(*args)
+ end
+end
diff --git a/actionpack/test/dispatch/runner_test.rb b/actionpack/test/dispatch/runner_test.rb
index 969933c9ed..b76bf4a320 100644
--- a/actionpack/test/dispatch/runner_test.rb
+++ b/actionpack/test/dispatch/runner_test.rb
@@ -4,7 +4,6 @@ class RunnerTest < ActiveSupport::TestCase
test "runner preserves the setting of integration_session" do
runner = Class.new do
def before_setup
-
end
end.new
diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb
index 53b99ebbc4..757e26973f 100644
--- a/actionpack/test/dispatch/ssl_test.rb
+++ b/actionpack/test/dispatch/ssl_test.rb
@@ -102,7 +102,11 @@ class StrictTransportSecurityTest < SSLTest
def assert_hsts(expected, url: "https://example.org", hsts: { subdomains: true }, headers: {})
self.app = build_app ssl_options: { hsts: hsts }, headers: headers
get url
- assert_equal expected, response.headers["Strict-Transport-Security"]
+ if expected.nil?
+ assert_nil response.headers["Strict-Transport-Security"]
+ else
+ assert_equal expected, response.headers["Strict-Transport-Security"]
+ end
end
test "enabled by default" do
diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb
index d8bc96e3e0..0bdff68692 100644
--- a/actionpack/test/dispatch/static_test.rb
+++ b/actionpack/test/dispatch/static_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "abstract_unit"
require "zlib"
@@ -29,7 +31,7 @@ module StaticTests
end
def test_handles_urls_with_ascii_8bit
- assert_equal "Hello, World!", get("/doorkeeper%E3E4".force_encoding("ASCII-8BIT")).body
+ assert_equal "Hello, World!", get("/doorkeeper%E3E4".dup.force_encoding("ASCII-8BIT")).body
end
def test_handles_urls_with_ascii_8bit_on_win_31j
@@ -37,7 +39,7 @@ module StaticTests
Encoding.default_internal = "Windows-31J"
Encoding.default_external = "Windows-31J"
end
- assert_equal "Hello, World!", get("/doorkeeper%E3E4".force_encoding("ASCII-8BIT")).body
+ assert_equal "Hello, World!", get("/doorkeeper%E3E4".dup.force_encoding("ASCII-8BIT")).body
end
def test_handles_urls_with_null_byte
@@ -163,7 +165,7 @@ module StaticTests
assert_equal file_name, env["PATH_INFO"]
end
- def test_serves_gzip_with_propper_content_type_fallback
+ def test_serves_gzip_with_proper_content_type_fallback
file_name = "/gzip/foo.zoo"
response = get(file_name, "HTTP_ACCEPT_ENCODING" => "gzip")
assert_gzip file_name, response
@@ -224,7 +226,7 @@ module StaticTests
def assert_gzip(file_name, response)
expected = File.read("#{FIXTURE_LOAD_PATH}/#{public_path}" + file_name)
- actual = Zlib::GzipReader.new(StringIO.new(response.body)).read
+ actual = ActiveSupport::Gzip.decompress(response.body)
assert_equal expected, actual
end
diff --git a/actionpack/test/dispatch/system_testing/driver_test.rb b/actionpack/test/dispatch/system_testing/driver_test.rb
new file mode 100644
index 0000000000..34d27671bb
--- /dev/null
+++ b/actionpack/test/dispatch/system_testing/driver_test.rb
@@ -0,0 +1,35 @@
+require "abstract_unit"
+require "action_dispatch/system_testing/driver"
+
+class DriverTest < ActiveSupport::TestCase
+ test "initializing the driver" do
+ driver = ActionDispatch::SystemTesting::Driver.new(:selenium)
+ assert_equal :selenium, driver.instance_variable_get(:@name)
+ end
+
+ test "initializing the driver with a browser" do
+ driver = ActionDispatch::SystemTesting::Driver.new(:selenium, using: :chrome, screen_size: [1400, 1400], options: { url: "http://example.com/wd/hub" })
+ assert_equal :selenium, driver.instance_variable_get(:@name)
+ assert_equal :chrome, driver.instance_variable_get(:@browser)
+ assert_equal [1400, 1400], driver.instance_variable_get(:@screen_size)
+ assert_equal ({ url: "http://example.com/wd/hub" }), driver.instance_variable_get(:@options)
+ end
+
+ test "initializing the driver with a poltergeist" do
+ driver = ActionDispatch::SystemTesting::Driver.new(:poltergeist, screen_size: [1400, 1400], options: { js_errors: false })
+ assert_equal :poltergeist, driver.instance_variable_get(:@name)
+ assert_equal [1400, 1400], driver.instance_variable_get(:@screen_size)
+ assert_equal ({ js_errors: false }), driver.instance_variable_get(:@options)
+ end
+
+ test "initializing the driver with a webkit" do
+ driver = ActionDispatch::SystemTesting::Driver.new(:webkit, screen_size: [1400, 1400], options: { skip_image_loading: true })
+ assert_equal :webkit, driver.instance_variable_get(:@name)
+ assert_equal [1400, 1400], driver.instance_variable_get(:@screen_size)
+ assert_equal ({ skip_image_loading: true }), driver.instance_variable_get(:@options)
+ end
+
+ test "registerable? returns false if driver is rack_test" do
+ assert_not ActionDispatch::SystemTesting::Driver.new(:rack_test).send(:registerable?)
+ end
+end
diff --git a/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb b/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
new file mode 100644
index 0000000000..a83818fd80
--- /dev/null
+++ b/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
@@ -0,0 +1,41 @@
+require "abstract_unit"
+require "action_dispatch/system_testing/test_helpers/screenshot_helper"
+require "capybara/dsl"
+
+class ScreenshotHelperTest < ActiveSupport::TestCase
+ test "image path is saved in tmp directory" do
+ new_test = DrivenBySeleniumWithChrome.new("x")
+
+ assert_equal "tmp/screenshots/x.png", new_test.send(:image_path)
+ end
+
+ test "image path includes failures text if test did not pass" do
+ new_test = DrivenBySeleniumWithChrome.new("x")
+
+ new_test.stub :passed?, false do
+ assert_equal "tmp/screenshots/failures_x.png", new_test.send(:image_path)
+ end
+ end
+
+ test "image path does not include failures text if test skipped" do
+ new_test = DrivenBySeleniumWithChrome.new("x")
+
+ new_test.stub :passed?, false do
+ new_test.stub :skipped?, true do
+ assert_equal "tmp/screenshots/x.png", new_test.send(:image_path)
+ end
+ end
+ end
+end
+
+class RackTestScreenshotsTest < DrivenByRackTest
+ test "rack_test driver does not support screenshot" do
+ assert_not self.send(:supports_screenshot?)
+ end
+end
+
+class SeleniumScreenshotsTest < DrivenBySeleniumWithChrome
+ test "selenium driver supports screenshot" do
+ assert self.send(:supports_screenshot?)
+ end
+end
diff --git a/actionpack/test/dispatch/system_testing/server_test.rb b/actionpack/test/dispatch/system_testing/server_test.rb
new file mode 100644
index 0000000000..10412d6367
--- /dev/null
+++ b/actionpack/test/dispatch/system_testing/server_test.rb
@@ -0,0 +1,17 @@
+require "abstract_unit"
+require "capybara/dsl"
+require "action_dispatch/system_testing/server"
+
+class ServerTest < ActiveSupport::TestCase
+ setup do
+ ActionDispatch::SystemTesting::Server.new.run
+ end
+
+ test "initializing the server port" do
+ assert_includes Capybara.servers, :rails_puma
+ end
+
+ test "port is always included" do
+ assert Capybara.always_include_port, "expected Capybara.always_include_port to be true"
+ end
+end
diff --git a/actionpack/test/dispatch/system_testing/system_test_case_test.rb b/actionpack/test/dispatch/system_testing/system_test_case_test.rb
new file mode 100644
index 0000000000..53f1a1bb37
--- /dev/null
+++ b/actionpack/test/dispatch/system_testing/system_test_case_test.rb
@@ -0,0 +1,65 @@
+require "abstract_unit"
+
+class SetDriverToRackTestTest < DrivenByRackTest
+ test "uses rack_test" do
+ assert_equal :rack_test, Capybara.current_driver
+ end
+end
+
+class OverrideSeleniumSubclassToRackTestTest < DrivenBySeleniumWithChrome
+ driven_by :rack_test
+
+ test "uses rack_test" do
+ assert_equal :rack_test, Capybara.current_driver
+ end
+end
+
+class SetDriverToSeleniumTest < DrivenBySeleniumWithChrome
+ test "uses selenium" do
+ assert_equal :selenium, Capybara.current_driver
+ end
+end
+
+class SetHostTest < DrivenByRackTest
+ test "sets default host" do
+ assert_equal "http://127.0.0.1", Capybara.app_host
+ end
+
+ test "overrides host" do
+ host! "http://example.com"
+
+ assert_equal "http://example.com", Capybara.app_host
+ end
+end
+
+class UndefMethodsTest < DrivenBySeleniumWithChrome
+ test "get" do
+ assert_raise NoMethodError do
+ get "http://example.com"
+ end
+ end
+
+ test "post" do
+ assert_raise NoMethodError do
+ post "http://example.com"
+ end
+ end
+
+ test "put" do
+ assert_raise NoMethodError do
+ put "http://example.com"
+ end
+ end
+
+ test "patch" do
+ assert_raise NoMethodError do
+ patch "http://example.com"
+ end
+ end
+
+ test "delete" do
+ assert_raise NoMethodError do
+ delete "http://example.com"
+ end
+ end
+end
diff --git a/actionpack/test/dispatch/uploaded_file_test.rb b/actionpack/test/dispatch/uploaded_file_test.rb
index 51680216e4..0074d2a314 100644
--- a/actionpack/test/dispatch/uploaded_file_test.rb
+++ b/actionpack/test/dispatch/uploaded_file_test.rb
@@ -13,6 +13,12 @@ module ActionDispatch
assert_equal "foo", uf.original_filename
end
+ def test_filename_is_different_object
+ file_str = "foo"
+ uf = Http::UploadedFile.new(filename: file_str, tempfile: Object.new)
+ assert_not_equal file_str.object_id , uf.original_filename.object_id
+ end
+
def test_filename_should_be_in_utf_8
uf = Http::UploadedFile.new(filename: "foo", tempfile: Object.new)
assert_equal "UTF-8", uf.original_filename.encoding.to_s
diff --git a/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb b/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb
index 9b88fa1f5a..dfcd423978 100644
--- a/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb
+++ b/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.html.erb
@@ -1,3 +1,3 @@
<body>
-<%= cache do %><p>ERB</p><% end %>
+<%= cache("fragment") do %><p>ERB</p><% end %>
</body>
diff --git a/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder b/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder
index efdcc28e0f..6599579740 100644
--- a/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder
+++ b/actionpack/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder
@@ -1,5 +1,5 @@
xml.body do
- cache do
+ cache("fragment") do
xml.p "Builder"
end
end
diff --git a/actionpack/test/fixtures/functional_caching/formatted_fragment_cached_with_variant.html+phone.erb b/actionpack/test/fixtures/functional_caching/formatted_fragment_cached_with_variant.html+phone.erb
index e523b74ae3..abf7017ce6 100644
--- a/actionpack/test/fixtures/functional_caching/formatted_fragment_cached_with_variant.html+phone.erb
+++ b/actionpack/test/fixtures/functional_caching/formatted_fragment_cached_with_variant.html+phone.erb
@@ -1,3 +1,3 @@
<body>
-<%= cache do %><p>PHONE</p><% end %>
+<%= cache("fragment") do %><p>PHONE</p><% end %>
</body>
diff --git a/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb b/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb
index fa5e6bd318..1148d83ad7 100644
--- a/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb
+++ b/actionpack/test/fixtures/functional_caching/fragment_cached.html.erb
@@ -1,3 +1,3 @@
Hello
-<%= cache do %>This bit's fragment cached<% end %>
+<%= cache "fragment" do %>This bit's fragment cached<% end %>
<%= 'Ciao' %>
diff --git a/actionpack/test/fixtures/layouts/builder.builder b/actionpack/test/fixtures/layouts/builder.builder
index 7c7d4b2dd1..c55488edd0 100644
--- a/actionpack/test/fixtures/layouts/builder.builder
+++ b/actionpack/test/fixtures/layouts/builder.builder
@@ -1,3 +1,3 @@
xml.wrapper do
xml << yield
-end \ No newline at end of file
+end
diff --git a/actionpack/test/fixtures/old_content_type/render_default_for_builder.builder b/actionpack/test/fixtures/old_content_type/render_default_for_builder.builder
index 598d62e2fc..15c8a7f5cf 100644
--- a/actionpack/test/fixtures/old_content_type/render_default_for_builder.builder
+++ b/actionpack/test/fixtures/old_content_type/render_default_for_builder.builder
@@ -1 +1 @@
-xml.p "Hello world!" \ No newline at end of file
+xml.p "Hello world!"
diff --git a/actionpack/test/fixtures/respond_to/using_defaults.xml.builder b/actionpack/test/fixtures/respond_to/using_defaults.xml.builder
index 598d62e2fc..15c8a7f5cf 100644
--- a/actionpack/test/fixtures/respond_to/using_defaults.xml.builder
+++ b/actionpack/test/fixtures/respond_to/using_defaults.xml.builder
@@ -1 +1 @@
-xml.p "Hello world!" \ No newline at end of file
+xml.p "Hello world!"
diff --git a/actionpack/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder b/actionpack/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder
index 598d62e2fc..15c8a7f5cf 100644
--- a/actionpack/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder
+++ b/actionpack/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder
@@ -1 +1 @@
-xml.p "Hello world!" \ No newline at end of file
+xml.p "Hello world!"
diff --git a/actionpack/test/fixtures/test/formatted_xml_erb.builder b/actionpack/test/fixtures/test/formatted_xml_erb.builder
index 14fd3549fb..f98aaa34a5 100644
--- a/actionpack/test/fixtures/test/formatted_xml_erb.builder
+++ b/actionpack/test/fixtures/test/formatted_xml_erb.builder
@@ -1 +1 @@
-xml.test 'failed' \ No newline at end of file
+xml.test "failed"
diff --git a/actionpack/test/fixtures/test/hello_xml_world.builder b/actionpack/test/fixtures/test/hello_xml_world.builder
index e7081b89fe..d16bb6b5cb 100644
--- a/actionpack/test/fixtures/test/hello_xml_world.builder
+++ b/actionpack/test/fixtures/test/hello_xml_world.builder
@@ -8,4 +8,4 @@ xml.html do
xml.p "monks"
xml.p "wiseguys"
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/journey/gtg/transition_table_test.rb b/actionpack/test/journey/gtg/transition_table_test.rb
index c7315c0338..889640fdd7 100644
--- a/actionpack/test/journey/gtg/transition_table_test.rb
+++ b/actionpack/test/journey/gtg/transition_table_test.rb
@@ -35,25 +35,25 @@ module ActionDispatch
def test_simulate_gt
sim = simulator_for ["/foo", "/bar"]
- assert_match sim, "/foo"
+ assert_match_route sim, "/foo"
end
def test_simulate_gt_regexp
sim = simulator_for [":foo"]
- assert_match sim, "foo"
+ assert_match_route sim, "foo"
end
def test_simulate_gt_regexp_mix
sim = simulator_for ["/get", "/:method/foo"]
- assert_match sim, "/get"
- assert_match sim, "/get/foo"
+ assert_match_route sim, "/get"
+ assert_match_route sim, "/get/foo"
end
def test_simulate_optional
sim = simulator_for ["/foo(/bar)"]
- assert_match sim, "/foo"
- assert_match sim, "/foo/bar"
- assert_no_match sim, "/foo/"
+ assert_match_route sim, "/foo"
+ assert_match_route sim, "/foo/bar"
+ assert_no_match_route sim, "/foo/"
end
def test_match_data
@@ -65,11 +65,11 @@ module ActionDispatch
sim = GTG::Simulator.new tt
- match = sim.match "/get"
- assert_equal [paths.first], match.memos
+ memos = sim.memos "/get"
+ assert_equal [paths.first], memos
- match = sim.match "/get/foo"
- assert_equal [paths.last], match.memos
+ memos = sim.memos "/get/foo"
+ assert_equal [paths.last], memos
end
def test_match_data_ambiguous
@@ -86,8 +86,8 @@ module ActionDispatch
builder = GTG::Builder.new ast
sim = GTG::Simulator.new builder.transition_table
- match = sim.match "/articles/new"
- assert_equal [paths[1], paths[3]], match.memos
+ memos = sim.memos "/articles/new"
+ assert_equal [paths[1], paths[3]], memos
end
private
@@ -109,6 +109,14 @@ module ActionDispatch
def simulator_for(paths)
GTG::Simulator.new tt(paths)
end
+
+ def assert_match_route(simulator, path)
+ assert simulator.memos(path), "Simulator should match #{path}."
+ end
+
+ def assert_no_match_route(simulator, path)
+ assert_not simulator.memos(path) { nil }, "Simulator should not match #{path}."
+ end
end
end
end
diff --git a/actionpack/test/journey/path/pattern_test.rb b/actionpack/test/journey/path/pattern_test.rb
index d61a8c023a..2c74617944 100644
--- a/actionpack/test/journey/path/pattern_test.rb
+++ b/actionpack/test/journey/path/pattern_test.rb
@@ -20,7 +20,7 @@ module ActionDispatch
"/:controller/*foo/bar" => %r{\A/(#{x})/(.+)/bar\Z},
"/:foo|*bar" => %r{\A/(?:([^/.?]+)|(.+))\Z},
}.each do |path, expected|
- define_method(:"test_to_regexp_#{path}") do
+ define_method(:"test_to_regexp_#{Regexp.escape(path)}") do
path = Pattern.build(
path,
{ controller: /.+/ },
@@ -44,7 +44,7 @@ module ActionDispatch
"/:controller/*foo/bar" => %r{\A/(#{x})/(.+)/bar},
"/:foo|*bar" => %r{\A/(?:([^/.?]+)|(.+))},
}.each do |path, expected|
- define_method(:"test_to_non_anchored_regexp_#{path}") do
+ define_method(:"test_to_non_anchored_regexp_#{Regexp.escape(path)}") do
path = Pattern.build(
path,
{ controller: /.+/ },
@@ -67,7 +67,7 @@ module ActionDispatch
"/:controller/*foo" => %w{ controller foo },
"/:controller/*foo/bar" => %w{ controller foo },
}.each do |path, expected|
- define_method(:"test_names_#{path}") do
+ define_method(:"test_names_#{Regexp.escape(path)}") do
path = Pattern.build(
path,
{ controller: /.+/ },
diff --git a/actionpack/test/journey/router/utils_test.rb b/actionpack/test/journey/router/utils_test.rb
index b77bf6628a..646563f7ab 100644
--- a/actionpack/test/journey/router/utils_test.rb
+++ b/actionpack/test/journey/router/utils_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "abstract_unit"
module ActionDispatch
@@ -21,7 +23,7 @@ module ActionDispatch
end
def test_uri_unescape_with_utf8_string
- assert_equal "Šašinková", Utils.unescape_uri("%C5%A0a%C5%A1inkov%C3%A1".force_encoding(Encoding::US_ASCII))
+ assert_equal "Šašinková", Utils.unescape_uri("%C5%A0a%C5%A1inkov%C3%A1".dup.force_encoding(Encoding::US_ASCII))
end
def test_normalize_path_not_greedy
@@ -31,6 +33,15 @@ module ActionDispatch
def test_normalize_path_uppercase
assert_equal "/foo%AAbar%AAbaz", Utils.normalize_path("/foo%aabar%aabaz")
end
+
+ def test_normalize_path_maintains_string_encoding
+ path = "/foo%AAbar%AAbaz".b
+ assert_equal Encoding::ASCII_8BIT, Utils.normalize_path(path).encoding
+ end
+
+ def test_normalize_path_with_nil
+ assert_equal '/', Utils.normalize_path(nil)
+ end
end
end
end
diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb
index 046b4167bb..ff37d85ed8 100644
--- a/actionpack/test/lib/controller/fake_models.rb
+++ b/actionpack/test/lib/controller/fake_models.rb
@@ -1,6 +1,6 @@
require "active_model"
-class Customer < Struct.new(:name, :id)
+Customer = Struct.new(:name, :id) do
extend ActiveModel::Naming
include ActiveModel::Conversion
@@ -26,9 +26,13 @@ class Customer < Struct.new(:name, :id)
def persisted?
id.present?
end
+
+ def cache_key
+ "#{name}/#{id}"
+ end
end
-class Post < Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost)
+Post = Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost) do
extend ActiveModel::Naming
include ActiveModel::Conversion
extend ActiveModel::Translation