diff options
Diffstat (limited to 'actionpack')
62 files changed, 470 insertions, 570 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 6921f1b45f..98bf9c944b 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,252 +1,41 @@ -* Update the default HSTS max-age value to 31536000 seconds (1 year) - to meet the minimum max-age requirement for https://hstspreload.org/. +## Rails 6.0.0.alpha (Unreleased) ## - *Grant Bourque* +* Add support for automatic nonce generation for Rails UJS -* Add `Referrer-Policy` header to default headers set. + Because the UJS library creates a script tag to process responses it + normally requires the script-src attribute of the content security + policy to include 'unsafe-inline'. - *Guillermo Iguaran* + To work around this we generate a per-request nonce value that is + embedded in a meta tag in a similar fashion to how CSRF protection + embeds its token in a meta tag. The UJS library can then read the + nonce value and set it on the dynamically generated script tag to + enable it to execute without needing 'unsafe-inline' enabled. -* Changed the system tests to set Puma as default server only when the - user haven't specified manually another server. + Nonce generation isn't 100% safe - if your script tag is including + user generated content in someway then it may be possible to exploit + an XSS vulnerability which can take advantage of the nonce. It is + however an improvement on a blanket permission for inline scripts. - *Guillermo Iguaran* + It is also possible to use the nonce within your own script tags by + using `nonce: true` to set the nonce value on the tag, e.g -* Add secure `X-Download-Options` and `X-Permitted-Cross-Domain-Policies` to - default headers set. + <%= javascript_tag nonce: true do %> + alert('Hello, World!'); + <% end %> - *Guillermo Iguaran* - -* Add headless firefox support to System Tests. - - *bogdanvlviv* - -* Changed the default system test screenshot output from `inline` to `simple`. - - `inline` works well for iTerm2 but not everyone uses iTerm2. Some terminals like - Terminal.app ignore the `inline` and output the path to the file since it can't - render the image. Other terminals, like those on Ubuntu, cannot handle the image - inline, but also don't handle it gracefully and instead of outputting the file - path, it dumps binary into the terminal. - - Commit 9d6e28 fixes this by changing the default for screenshot to be `simple`. - - *Eileen M. Uchitelle* - -* Register most popular audio/video/font mime types supported by modern browsers. - - *Guillermo Iguaran* - -* Fix optimized url helpers when using relative url root - - Fixes #31220. + Fixes #31689. *Andrew White* +* Rails 6 requires Ruby 2.4.1 or newer. -## Rails 5.2.0.beta2 (November 28, 2017) ## - -* No changes. - - -## Rails 5.2.0.beta1 (November 27, 2017) ## - -* Add DSL for configuring Content-Security-Policy header - - The DSL allows you to configure a global Content-Security-Policy - header and then override within a controller. For more information - about the Content-Security-Policy header see MDN: - - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy - - Example global policy: - - # config/initializers/content_security_policy.rb - Rails.application.config.content_security_policy do |p| - p.default_src :self, :https - p.font_src :self, :https, :data - p.img_src :self, :https, :data - p.object_src :none - p.script_src :self, :https - p.style_src :self, :https, :unsafe_inline - end - - Example controller overrides: - - # Override policy inline - class PostsController < ApplicationController - content_security_policy do |p| - p.upgrade_insecure_requests true - end - end - - # Using literal values - class PostsController < ApplicationController - content_security_policy do |p| - p.base_uri "https://www.example.com" - end - end - - # Using mixed static and dynamic values - class PostsController < ApplicationController - content_security_policy do |p| - p.base_uri :self, -> { "https://#{current_user.domain}.example.com" } - end - end - - Allows you to also only report content violations for migrating - legacy content using the `content_security_policy_report_only` - configuration attribute, e.g; - - # config/initializers/content_security_policy.rb - Rails.application.config.content_security_policy_report_only = true - - # controller override - class PostsController < ApplicationController - self.content_security_policy_report_only = true - end - - Note that this feature does not validate the header for performance - reasons since the header is calculated at runtime. - - *Andrew White* - -* Make `assert_recognizes` to traverse mounted engines - - *Yuichiro Kaneko* - -* Remove deprecated `ActionController::ParamsParser::ParseError`. - - *Rafael Mendonça França* - -* Add `:allow_other_host` option to `redirect_back` method. - - When `allow_other_host` is set to `false`, the `redirect_back` will not allow redirecting from a - different host. `allow_other_host` is `true` by default. - - *Tim Masliuchenko* - -* Add headless chrome support to System Tests. - - *Yuji Yaginuma* - -* Add ability to enable Early Hints for HTTP/2 - - If supported by the server, and enabled in Puma this allows H2 Early Hints to be used. - - The `javascript_include_tag` and the `stylesheet_link_tag` automatically add Early Hints if requested. - - *Eileen M. Uchitelle*, *Aaron Patterson* - -* Simplify cookies middleware with key rotation support - - Use the `rotate` method for both `MessageEncryptor` and - `MessageVerifier` to add key rotation support for encrypted and - signed cookies. This also helps simplify support for legacy cookie - security. - - *Michael J Coyne* - -* Use Capybara registered `:puma` server config. - - The Capybara registered `:puma` server ensures the puma server is run in process so - connection sharing and open request detection work correctly by default. - - *Thomas Walpole* - -* Cookies `:expires` option supports `ActiveSupport::Duration` object. - - cookies[:user_name] = { value: "assain", expires: 1.hour } - cookies[:key] = { value: "a yummy cookie", expires: 6.months } - - Pull Request: #30121 - - *Assain Jaleel* - -* Enforce signed/encrypted cookie expiry server side. - - Rails can thwart attacks by malicious clients that don't honor a cookie's expiry. - - It does so by stashing the expiry within the written cookie and relying on the - signing/encrypting to vouch that it hasn't been tampered with. Then on a - server-side read, the expiry is verified and any expired cookie is discarded. - - Pull Request: #30121 - - *Assain Jaleel* - -* Make `take_failed_screenshot` work within engine. - - Fixes #30405. - - *Yuji Yaginuma* - -* Deprecate `ActionDispatch::TestResponse` response aliases. - - `#success?`, `#missing?` & `#error?` are not supported by the actual - `ActionDispatch::Response` object and can produce false-positives. Instead, - use the response helpers provided by `Rack::Response`. - - *Trevor Wistaff* - -* Protect from forgery by default - - Rather than protecting from forgery in the generated `ApplicationController`, - add it to `ActionController::Base` depending on - `config.action_controller.default_protect_from_forgery`. This configuration - defaults to false to support older versions which have removed it from their - `ApplicationController`, but is set to true for Rails 5.2. - - *Lisa Ugray* - -* Fallback `ActionController::Parameters#to_s` to `Hash#to_s`. - - *Kir Shatrov* - -* `driven_by` now registers poltergeist and capybara-webkit. - - If poltergeist or capybara-webkit are set as drivers is set for System Tests, - `driven_by` will register the driver and set additional options passed via - the `:options` parameter. - - Refer to the respective driver's documentation to see what options can be passed. - - *Mario Chavez* - -* AEAD encrypted cookies and sessions with GCM. - - Encrypted cookies now use AES-GCM which couples authentication and - encryption in one faster step and produces shorter ciphertexts. Cookies - encrypted using AES in CBC HMAC mode will be seamlessly upgraded when - this new mode is enabled via the - `action_dispatch.use_authenticated_cookie_encryption` configuration value. - - *Michael J Coyne* - -* Change the cache key format for fragments to make it easier to debug key churn. The new format is: - - views/template/action.html.erb:7a1156131a6928cb0026877f8b749ac9/projects/123 - ^template path ^template tree digest ^class ^id - - *DHH* - -* Add support for recyclable cache keys with fragment caching. This uses the new versioned entries in the - `ActiveSupport::Cache` stores and relies on the fact that Active Record has split `#cache_key` and `#cache_version` - to support it. - - *DHH* - -* Add `action_controller_api` and `action_controller_base` load hooks to be called in `ActiveSupport.on_load` - - `ActionController::Base` and `ActionController::API` have differing implementations. This means that - the one umbrella hook `action_controller` is not able to address certain situations where a method - may not exist in a certain implementation. - - This is fixed by adding two new hooks so you can target `ActionController::Base` vs `ActionController::API` + *Jeremy Daer* - Fixes #27013. +* Add alias method `to_hash` to `to_h` for `cookies`. + Add alias method `to_h` to `to_hash` for `session`. - *Julian Nadeau* + *Igor Kasyanchuk* -Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/actionpack/CHANGELOG.md) for previous changes. +Please check [5-2-stable](https://github.com/rails/rails/blob/5-2-stable/actionpack/CHANGELOG.md) for previous changes. diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 33d42e69d8..1dc8abf746 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |s| s.summary = "Web-flow and rendering framework putting the VC in MVC (part of Rails)." s.description = "Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server." - s.required_ruby_version = ">= 2.2.2" + s.required_ruby_version = ">= 2.4.1" s.license = "MIT" diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 457884ea08..f875aa5e6b 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -230,18 +230,16 @@ module ActionController # Returns a Rack endpoint for the given action name. def self.action(name) + app = lambda { |env| + req = ActionDispatch::Request.new(env) + res = make_response! req + new.dispatch(name, req, res) + } + if middleware_stack.any? - middleware_stack.build(name) do |env| - req = ActionDispatch::Request.new(env) - res = make_response! req - new.dispatch(name, req, res) - end + middleware_stack.build(name, app) else - lambda { |env| - req = ActionDispatch::Request.new(env) - res = make_response! req - new.dispatch(name, req, res) - } + app end end diff --git a/actionpack/lib/action_controller/metal/content_security_policy.rb b/actionpack/lib/action_controller/metal/content_security_policy.rb index 48a7109bea..95f2f3242d 100644 --- a/actionpack/lib/action_controller/metal/content_security_policy.rb +++ b/actionpack/lib/action_controller/metal/content_security_policy.rb @@ -5,6 +5,14 @@ module ActionController #:nodoc: # TODO: Documentation extend ActiveSupport::Concern + include AbstractController::Helpers + include AbstractController::Callbacks + + included do + helper_method :content_security_policy? + helper_method :content_security_policy_nonce + end + module ClassMethods def content_security_policy(**options, &block) before_action(options) do @@ -22,5 +30,15 @@ module ActionController #:nodoc: end end end + + private + + def content_security_policy? + request.content_security_policy + end + + def content_security_policy_nonce + request.content_security_policy_nonce + end end end diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 0ab313e398..94092de96c 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -3,7 +3,6 @@ require "rack/session/abstract/id" require "action_controller/metal/exceptions" require "active_support/security_utils" -require "active_support/core_ext/string/strip" module ActionController #:nodoc: class InvalidAuthenticityToken < ActionControllerError #:nodoc: @@ -416,7 +415,7 @@ module ActionController #:nodoc: allow_forgery_protection end - NULL_ORIGIN_MESSAGE = <<-MSG.strip_heredoc + NULL_ORIGIN_MESSAGE = <<~MSG The browser returned a 'null' origin for a request with origin-based forgery protection turned on. This usually means you have the 'no-referrer' Referrer-Policy header enabled, or that you the request came from a site that refused to give its origin. This makes it impossible for Rails to verify the source of the requests. Likely the diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index a56ac749f8..615c90c496 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "active_support/core_ext/hash/indifferent_access" -require "active_support/core_ext/hash/transform_values" require "active_support/core_ext/array/wrap" require "active_support/core_ext/string/filters" require "active_support/core_ext/object/to_query" diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb index 4b408750a4..798d142755 100644 --- a/actionpack/lib/action_controller/test_case.rb +++ b/actionpack/lib/action_controller/test_case.rb @@ -256,7 +256,7 @@ module ActionController # # def test_create # json = {book: { title: "Love Hina" }}.to_json - # post :create, json + # post :create, body: json # end # # == Special instance variables diff --git a/actionpack/lib/action_dispatch/http/content_security_policy.rb b/actionpack/lib/action_dispatch/http/content_security_policy.rb index 4883e23d24..a3407c9698 100644 --- a/actionpack/lib/action_dispatch/http/content_security_policy.rb +++ b/actionpack/lib/action_dispatch/http/content_security_policy.rb @@ -21,6 +21,12 @@ module ActionDispatch #:nodoc: return response if policy_present?(headers) if policy = request.content_security_policy + if policy.directives["script-src"] + if nonce = request.content_security_policy_nonce + policy.directives["script-src"] << "'nonce-#{nonce}'" + end + end + headers[header_name(request)] = policy.build(request.controller_instance) end @@ -51,6 +57,8 @@ module ActionDispatch #:nodoc: module Request POLICY = "action_dispatch.content_security_policy".freeze POLICY_REPORT_ONLY = "action_dispatch.content_security_policy_report_only".freeze + NONCE_GENERATOR = "action_dispatch.content_security_policy_nonce_generator".freeze + NONCE = "action_dispatch.content_security_policy_nonce".freeze def content_security_policy get_header(POLICY) @@ -67,6 +75,30 @@ module ActionDispatch #:nodoc: def content_security_policy_report_only=(value) set_header(POLICY_REPORT_ONLY, value) end + + def content_security_policy_nonce_generator + get_header(NONCE_GENERATOR) + end + + def content_security_policy_nonce_generator=(generator) + set_header(NONCE_GENERATOR, generator) + end + + def content_security_policy_nonce + if content_security_policy_nonce_generator + if nonce = get_header(NONCE) + nonce + else + set_header(NONCE, generate_content_security_policy_nonce) + end + end + end + + private + + def generate_content_security_policy_nonce + content_security_policy_nonce_generator.call(self) + end end MAPPINGS = { @@ -172,7 +204,7 @@ module ActionDispatch #:nodoc: end def build(context = nil) - build_directives(context).compact.join("; ") + ";" + build_directives(context).compact.join("; ") end private diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index d2b2106845..295539281f 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -279,8 +279,6 @@ module Mime def all?; false; end - # TODO Change this to private once we've dropped Ruby 2.2 support. - # Workaround for Ruby 2.2 "private attribute?" warning. protected attr_reader :string, :synonyms diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index f0344fd927..35ba44005a 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -274,7 +274,7 @@ module ActionDispatch def standard_port case protocol when "https://" then 443 - else 80 + else 80 end end diff --git a/actionpack/lib/action_dispatch/journey/nodes/node.rb b/actionpack/lib/action_dispatch/journey/nodes/node.rb index 08b931a3cd..32f632800c 100644 --- a/actionpack/lib/action_dispatch/journey/nodes/node.rb +++ b/actionpack/lib/action_dispatch/journey/nodes/node.rb @@ -32,7 +32,7 @@ module ActionDispatch end def name - left.tr "*:".freeze, "".freeze + -left.tr("*:", "") end def type @@ -82,7 +82,7 @@ module ActionDispatch def initialize(left) super @regexp = DEFAULT_EXP - @name = left.tr "*:".freeze, "".freeze + @name = -left.tr("*:", "") end def default_regexp? diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb index 2d85a89a56..537f479ee5 100644 --- a/actionpack/lib/action_dispatch/journey/path/pattern.rb +++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb @@ -90,7 +90,7 @@ module ActionDispatch return @separator_re unless @matchers.key?(node) re = @matchers[node] - "(#{re})" + "(#{Regexp.union(re)})" end def visit_GROUP(node) @@ -183,7 +183,7 @@ module ActionDispatch node = node.to_sym if @requirements.key?(node) - re = /#{@requirements[node]}|/ + re = /#{Regexp.union(@requirements[node])}|/ @offsets.push((re.match("").length - 1) + @offsets.last) else @offsets << @offsets.last diff --git a/actionpack/lib/action_dispatch/journey/scanner.rb b/actionpack/lib/action_dispatch/journey/scanner.rb index 4ae77903fa..2a075862e9 100644 --- a/actionpack/lib/action_dispatch/journey/scanner.rb +++ b/actionpack/lib/action_dispatch/journey/scanner.rb @@ -34,6 +34,13 @@ module ActionDispatch private + # takes advantage of String @- deduping capabilities in Ruby 2.5 upwards + # see: https://bugs.ruby-lang.org/issues/13077 + def dedup_scan(regex) + r = @ss.scan(regex) + r ? -r : nil + end + def scan case # / @@ -47,15 +54,15 @@ module ActionDispatch [:OR, "|"] when @ss.skip(/\./) [:DOT, "."] - when text = @ss.scan(/:\w+/) + when text = dedup_scan(/:\w+/) [:SYMBOL, text] - when text = @ss.scan(/\*\w+/) + when text = dedup_scan(/\*\w+/) [:STAR, text] when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/) text.tr! "\\", "" - [:LITERAL, text] + [:LITERAL, -text] # any char - when text = @ss.scan(/./) + when text = dedup_scan(/./) [:LITERAL, text] end end diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index ea4156c972..c45d947904 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -338,6 +338,9 @@ module ActionDispatch end alias :has_key? :key? + # Returns the cookies as Hash. + alias :to_hash :to_h + def update(other_hash) @cookies.update other_hash.stringify_keys self diff --git a/actionpack/lib/action_dispatch/middleware/request_id.rb b/actionpack/lib/action_dispatch/middleware/request_id.rb index 805d3f2148..da2871b551 100644 --- a/actionpack/lib/action_dispatch/middleware/request_id.rb +++ b/actionpack/lib/action_dispatch/middleware/request_id.rb @@ -30,7 +30,7 @@ module ActionDispatch private def make_request_id(request_id) if request_id.presence - request_id.gsub(/[^\w\-]/, "".freeze).first(255) + request_id.gsub(/[^\w\-@]/, "".freeze).first(255) else internal_request_id end diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb index d86d0b10c2..000847e193 100644 --- a/actionpack/lib/action_dispatch/request/session.rb +++ b/actionpack/lib/action_dispatch/request/session.rb @@ -130,6 +130,7 @@ module ActionDispatch load_for_read! @delegate.dup.delete_if { |_, v| v.nil? } end + alias :to_h :to_hash # Updates the session with given Hash. # diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb index a2205569b4..22336c59b6 100644 --- a/actionpack/lib/action_dispatch/routing/inspector.rb +++ b/actionpack/lib/action_dispatch/routing/inspector.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "delegate" -require "active_support/core_ext/string/strip" module ActionDispatch module Routing @@ -150,10 +149,10 @@ module ActionDispatch def no_routes(routes) @buffer << if routes.none? - <<-MESSAGE.strip_heredoc - You don't have any routes defined! + <<~MESSAGE + You don't have any routes defined! - Please add some routes in config/routes.rb. + Please add some routes in config/routes.rb. MESSAGE else "No routes were found for this controller" @@ -203,7 +202,7 @@ module ActionDispatch end def no_routes(*) - @buffer << <<-MESSAGE.strip_heredoc + @buffer << <<~MESSAGE <p>You don't have any routes defined!</p> <ul> <li>Please add some routes in <tt>config/routes.rb</tt>.</li> diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index d87a23a58c..f3970d5445 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -611,7 +611,7 @@ module ActionDispatch end raise ArgumentError, "A rack application must be specified" unless app.respond_to?(:call) - raise ArgumentError, <<-MSG.strip_heredoc unless path + raise ArgumentError, <<~MSG unless path Must be called with mount point mount SomeRackApp, at: "some_route" @@ -1573,7 +1573,7 @@ module ActionDispatch # Matches a URL pattern to one or more routes. # For more information, see match[rdoc-ref:Base#match]. # - # match 'path' => 'controller#action', via: patch + # match 'path' => 'controller#action', via: :patch # match 'path', to: 'controller#action', via: :post # match 'path', 'otherpath', on: :member, via: :get def match(path, *rest, &block) @@ -2082,9 +2082,9 @@ module ActionDispatch # [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ] # end # - # In this instance the +params+ object comes from the context in which the the + # In this instance the +params+ object comes from the context in which the # block is executed, e.g. generating a URL inside a controller action or a view. - # If the block is executed where there isn't a params object such as this: + # If the block is executed where there isn't a +params+ object such as this: # # Rails.application.routes.url_helpers.browse_path # diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 9eff30fa53..a29a5a04ef 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -2,7 +2,6 @@ require "action_dispatch/journey" require "active_support/core_ext/object/to_query" -require "active_support/core_ext/hash/slice" require "active_support/core_ext/module/redefine_method" require "active_support/core_ext/module/remove_method" require "active_support/core_ext/array/extract_options" @@ -154,13 +153,13 @@ module ActionDispatch url_name = :"#{name}_url" @path_helpers_module.module_eval do - define_method(path_name) do |*args| + redefine_method(path_name) do |*args| helper.call(self, args, true) end end @url_helpers_module.module_eval do - define_method(url_name) do |*args| + redefine_method(url_name) do |*args| helper.call(self, args, false) end end @@ -855,7 +854,7 @@ module ActionDispatch recognize_path_with_request(req, path, extras) end - def recognize_path_with_request(req, path, extras) + def recognize_path_with_request(req, path, extras, raise_on_missing: true) @router.recognize(req) do |route, params| params.merge!(extras) params.each do |key, value| @@ -875,12 +874,14 @@ module ActionDispatch return req.path_parameters elsif app.matches?(req) && app.engine? - path_parameters = app.rack_app.routes.recognize_path_with_request(req, path, extras) - return path_parameters + path_parameters = app.rack_app.routes.recognize_path_with_request(req, path, extras, raise_on_missing: false) + return path_parameters if path_parameters end end - raise ActionController::RoutingError, "No route matches #{path.inspect}" + if raise_on_missing + raise ActionController::RoutingError, "No route matches #{path.inspect}" + end end end # :startdoc: diff --git a/actionpack/lib/action_dispatch/system_test_case.rb b/actionpack/lib/action_dispatch/system_test_case.rb index 393141535b..f85f816bb9 100644 --- a/actionpack/lib/action_dispatch/system_test_case.rb +++ b/actionpack/lib/action_dispatch/system_test_case.rb @@ -6,6 +6,7 @@ require "capybara/dsl" require "capybara/minitest" require "action_controller" require "action_dispatch/system_testing/driver" +require "action_dispatch/system_testing/browser" require "action_dispatch/system_testing/server" require "action_dispatch/system_testing/test_helpers/screenshot_helper" require "action_dispatch/system_testing/test_helpers/setup_and_teardown" diff --git a/actionpack/lib/action_dispatch/system_testing/browser.rb b/actionpack/lib/action_dispatch/system_testing/browser.rb new file mode 100644 index 0000000000..10e6888ab3 --- /dev/null +++ b/actionpack/lib/action_dispatch/system_testing/browser.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module ActionDispatch + module SystemTesting + class Browser # :nodoc: + attr_reader :name + + def initialize(name) + @name = name + end + + def type + case name + when :headless_chrome + :chrome + when :headless_firefox + :firefox + else + name + end + end + + def options + case name + when :headless_chrome + headless_chrome_browser_options + when :headless_firefox + headless_firefox_browser_options + end + end + + private + def headless_chrome_browser_options + options = Selenium::WebDriver::Chrome::Options.new + options.args << "--headless" + options.args << "--disable-gpu" + + options + end + + def headless_firefox_browser_options + options = Selenium::WebDriver::Firefox::Options.new + options.args << "-headless" + + options + end + end + end +end diff --git a/actionpack/lib/action_dispatch/system_testing/driver.rb b/actionpack/lib/action_dispatch/system_testing/driver.rb index 280989a146..5252ff6746 100644 --- a/actionpack/lib/action_dispatch/system_testing/driver.rb +++ b/actionpack/lib/action_dispatch/system_testing/driver.rb @@ -5,7 +5,7 @@ module ActionDispatch class Driver # :nodoc: def initialize(name, **options) @name = name - @browser = options[:using] + @browser = Browser.new(options[:using]) @screen_size = options[:screen_size] @options = options[:options] end @@ -32,34 +32,11 @@ module ActionDispatch end def browser_options - if @browser == :headless_chrome - browser_options = Selenium::WebDriver::Chrome::Options.new - browser_options.args << "--headless" - browser_options.args << "--disable-gpu" - - @options.merge(options: browser_options) - elsif @browser == :headless_firefox - browser_options = Selenium::WebDriver::Firefox::Options.new - browser_options.args << "-headless" - - @options.merge(options: browser_options) - else - @options - end - end - - def browser - if @browser == :headless_chrome - :chrome - elsif @browser == :headless_firefox - :firefox - else - @browser - end + @options.merge(options: @browser.options).compact end def register_selenium(app) - Capybara::Selenium::Driver.new(app, { browser: browser }.merge(browser_options)).tap do |driver| + Capybara::Selenium::Driver.new(app, { browser: @browser.type }.merge(browser_options)).tap do |driver| driver.browser.manage.window.size = Selenium::WebDriver::Dimension.new(*@screen_size) end end diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb index 97f4934b58..37969fcb57 100644 --- a/actionpack/lib/action_pack/gem_version.rb +++ b/actionpack/lib/action_pack/gem_version.rb @@ -7,10 +7,10 @@ module ActionPack end module VERSION - MAJOR = 5 - MINOR = 2 + MAJOR = 6 + MINOR = 0 TINY = 0 - PRE = "beta2" + PRE = "alpha" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index f9a037e3cc..504c77b8ef 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -301,18 +301,18 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_empty_flash process :flash_me_naked - assert flash.empty? + assert_empty flash end def test_flash_exist process :flash_me - assert flash.any? - assert flash["hello"].present? + assert_predicate flash, :any? + assert_predicate flash["hello"], :present? end def test_flash_does_not_exist process :nothing - assert flash.empty? + assert_empty flash end def test_session_exist @@ -322,7 +322,7 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def session_does_not_exist process :nothing - assert session.empty? + assert_empty session end def test_redirection_location @@ -343,46 +343,46 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase def test_server_error_response_code process :response500 - assert @response.server_error? + assert_predicate @response, :server_error? process :response599 - assert @response.server_error? + assert_predicate @response, :server_error? process :response404 - assert !@response.server_error? + assert_not_predicate @response, :server_error? end def test_missing_response_code process :response404 - assert @response.not_found? + assert_predicate @response, :not_found? end def test_client_error_response_code process :response404 - assert @response.client_error? + assert_predicate @response, :client_error? end def test_redirect_url_match process :redirect_external - assert @response.redirect? + assert_predicate @response, :redirect? assert_match(/rubyonrails/, @response.redirect_url) assert !/perloffrails/.match(@response.redirect_url) end def test_redirection process :redirect_internal - assert @response.redirect? + assert_predicate @response, :redirect? process :redirect_external - assert @response.redirect? + assert_predicate @response, :redirect? process :nothing - assert !@response.redirect? + assert_not_predicate @response, :redirect? end def test_successful_response_code process :nothing - assert @response.successful? + assert_predicate @response, :successful? end def test_response_object diff --git a/actionpack/test/controller/api/conditional_get_test.rb b/actionpack/test/controller/api/conditional_get_test.rb index fd1997f26c..e366ce9532 100644 --- a/actionpack/test/controller/api/conditional_get_test.rb +++ b/actionpack/test/controller/api/conditional_get_test.rb @@ -53,7 +53,7 @@ class ConditionalGetApiTest < ActionController::TestCase @request.if_modified_since = @last_modified get :one assert_equal 304, @response.status.to_i - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal @last_modified, @response.headers["Last-Modified"] end end diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb index 9ac82c0d65..a672ede1a9 100644 --- a/actionpack/test/controller/base_test.rb +++ b/actionpack/test/controller/base_test.rb @@ -107,9 +107,9 @@ class ControllerInstanceTests < ActiveSupport::TestCase end def test_performed? - assert !@empty.performed? + assert_not_predicate @empty, :performed? @empty.response_body = ["sweet"] - assert @empty.performed? + assert_predicate @empty, :performed? end def test_action_methods diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 3557f9f888..8b596083d5 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -159,7 +159,7 @@ class FragmentCachingTest < ActionController::TestCase html_safe = @controller.read_fragment("name") assert_equal content, html_safe - assert html_safe.html_safe? + assert_predicate html_safe, :html_safe? end end @@ -382,7 +382,7 @@ class ViewCacheDependencyTest < ActionController::TestCase end def test_view_cache_dependencies_are_empty_by_default - assert NoDependenciesController.new.view_cache_dependencies.empty? + assert_empty NoDependenciesController.new.view_cache_dependencies end def test_view_cache_dependencies_are_listed_in_declaration_order diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index 9f0a9dec7a..2b16a555bb 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -819,7 +819,7 @@ class FilterTest < ActionController::TestCase response = test_process(RescuedController) end - assert response.successful? + assert_predicate response, :successful? assert_equal("I rescued this: #<FilterTest::ErrorToRescue: Something made the bad noise.>", response.body) end diff --git a/actionpack/test/controller/flash_hash_test.rb b/actionpack/test/controller/flash_hash_test.rb index f31a4d9329..6c3ac26de1 100644 --- a/actionpack/test/controller/flash_hash_test.rb +++ b/actionpack/test/controller/flash_hash_test.rb @@ -92,11 +92,11 @@ module ActionDispatch end def test_empty? - assert @hash.empty? + assert_empty @hash @hash["zomg"] = "bears" - assert !@hash.empty? + assert_not_empty @hash @hash.clear - assert @hash.empty? + assert_empty @hash end def test_each diff --git a/actionpack/test/controller/http_digest_authentication_test.rb b/actionpack/test/controller/http_digest_authentication_test.rb index 76ff784926..560157dc61 100644 --- a/actionpack/test/controller/http_digest_authentication_test.rb +++ b/actionpack/test/controller/http_digest_authentication_test.rb @@ -9,7 +9,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase before_action :authenticate_with_request, only: :display USERS = { "lifo" => "world", "pretty" => "please", - "dhh" => ::Digest::MD5::hexdigest(["dhh", "SuperSecret", "secret"].join(":")) } + "dhh" => ::Digest::MD5.hexdigest(["dhh", "SuperSecret", "secret"].join(":")) } def index render plain: "Hello Secret" @@ -181,9 +181,10 @@ class HttpDigestAuthenticationTest < ActionController::TestCase end test "authentication request with password stored as ha1 digest hash" do - @request.env["HTTP_AUTHORIZATION"] = encode_credentials(username: "dhh", - password: ::Digest::MD5::hexdigest(["dhh", "SuperSecret", "secret"].join(":")), - password_is_ha1: true) + @request.env["HTTP_AUTHORIZATION"] = encode_credentials( + username: "dhh", + password: ::Digest::MD5.hexdigest(["dhh", "SuperSecret", "secret"].join(":")), + password_is_ha1: true) get :display assert_response :success diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index fd1c5e693f..a685f5868e 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -14,11 +14,11 @@ class SessionTest < ActiveSupport::TestCase end def test_https_bang_works_and_sets_truth_by_default - assert !@session.https? + assert_not_predicate @session, :https? @session.https! - assert @session.https? + assert_predicate @session, :https? @session.https! false - assert !@session.https? + assert_not_predicate @session, :https? end def test_host! @@ -412,11 +412,11 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest get "/get_with_params", params: { foo: "bar" } - assert request.env["rack.input"].string.empty? + assert_empty request.env["rack.input"].string assert_equal "foo=bar", request.env["QUERY_STRING"] assert_equal "foo=bar", request.query_string assert_equal "bar", request.parameters["foo"] - assert request.parameters["leaks"].nil? + assert_predicate request.parameters["leaks"], :nil? end end diff --git a/actionpack/test/controller/metal_test.rb b/actionpack/test/controller/metal_test.rb index c3ebcb22b8..248ef36b7c 100644 --- a/actionpack/test/controller/metal_test.rb +++ b/actionpack/test/controller/metal_test.rb @@ -23,9 +23,9 @@ class MetalControllerInstanceTests < ActiveSupport::TestCase "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") + assert_not response_headers.key?("X-Frame-Options") + assert_not response_headers.key?("X-Content-Type-Options") + assert_not response_headers.key?("X-XSS-Protection") ensure ActionDispatch::Response.default_headers = original_default_headers end diff --git a/actionpack/test/controller/output_escaping_test.rb b/actionpack/test/controller/output_escaping_test.rb index e33a99068f..d683bc73e6 100644 --- a/actionpack/test/controller/output_escaping_test.rb +++ b/actionpack/test/controller/output_escaping_test.rb @@ -4,7 +4,7 @@ require "abstract_unit" class OutputEscapingTest < ActiveSupport::TestCase test "escape_html shouldn't die when passed nil" do - assert ERB::Util.h(nil).blank? + assert_predicate ERB::Util.h(nil), :blank? end test "escapeHTML should escape strings" do diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb index 154430d4b0..07a897a103 100644 --- a/actionpack/test/controller/parameters/accessors_test.rb +++ b/actionpack/test/controller/parameters/accessors_test.rb @@ -2,7 +2,6 @@ require "abstract_unit" require "action_controller/metal/strong_parameters" -require "active_support/core_ext/hash/transform_values" class ParametersAccessorsTest < ActiveSupport::TestCase setup do @@ -22,13 +21,13 @@ class ParametersAccessorsTest < ActiveSupport::TestCase test "[] retains permitted status" do @params.permit! - assert @params[:person].permitted? - assert @params[:person][:name].permitted? + assert_predicate @params[:person], :permitted? + assert_predicate @params[:person][:name], :permitted? end test "[] retains unpermitted status" do - assert_not @params[:person].permitted? - assert_not @params[:person][:name].permitted? + assert_not_predicate @params[:person], :permitted? + assert_not_predicate @params[:person][:name], :permitted? end test "as_json returns the JSON representation of the parameters hash" do @@ -78,33 +77,33 @@ class ParametersAccessorsTest < ActiveSupport::TestCase test "empty? returns true when params contains no key/value pairs" do params = ActionController::Parameters.new - assert params.empty? + assert_empty params end test "empty? returns false when any params are present" do - refute @params.empty? + assert_not_empty @params end test "except retains permitted status" do @params.permit! - assert @params.except(:person).permitted? - assert @params[:person].except(:name).permitted? + assert_predicate @params.except(:person), :permitted? + assert_predicate @params[:person].except(:name), :permitted? end test "except retains unpermitted status" do - assert_not @params.except(:person).permitted? - assert_not @params[:person].except(:name).permitted? + assert_not_predicate @params.except(:person), :permitted? + assert_not_predicate @params[:person].except(:name), :permitted? end test "fetch retains permitted status" do @params.permit! - assert @params.fetch(:person).permitted? - assert @params[:person].fetch(:name).permitted? + assert_predicate @params.fetch(:person), :permitted? + assert_predicate @params[:person].fetch(:name), :permitted? end test "fetch retains unpermitted status" do - assert_not @params.fetch(:person).permitted? - assert_not @params[:person].fetch(:name).permitted? + assert_not_predicate @params.fetch(:person), :permitted? + assert_not_predicate @params[:person].fetch(:name), :permitted? end test "has_key? returns true if the given key is present in the params" do @@ -112,7 +111,7 @@ class ParametersAccessorsTest < ActiveSupport::TestCase end test "has_key? returns false if the given key is not present in the params" do - refute @params.has_key?(:address) + assert_not @params.has_key?(:address) end test "has_value? returns true if the given value is present in the params" do @@ -122,7 +121,7 @@ class ParametersAccessorsTest < ActiveSupport::TestCase 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") + assert_not params.has_value?("New York") end test "include? returns true if the given key is present in the params" do @@ -130,7 +129,7 @@ class ParametersAccessorsTest < ActiveSupport::TestCase end test "include? returns false if the given key is not present in the params" do - refute @params.include?(:address) + assert_not @params.include?(:address) end test "key? returns true if the given key is present in the params" do @@ -138,7 +137,7 @@ class ParametersAccessorsTest < ActiveSupport::TestCase end test "key? returns false if the given key is not present in the params" do - refute @params.key?(:address) + assert_not @params.key?(:address) end test "keys returns an array of the keys of the params" do @@ -147,48 +146,48 @@ class ParametersAccessorsTest < ActiveSupport::TestCase end test "reject retains permitted status" do - assert_not @params.reject { |k| k == "person" }.permitted? + assert_not_predicate @params.reject { |k| k == "person" }, :permitted? end test "reject retains unpermitted status" do @params.permit! - assert @params.reject { |k| k == "person" }.permitted? + assert_predicate @params.reject { |k| k == "person" }, :permitted? end test "select retains permitted status" do @params.permit! - assert @params.select { |k| k == "person" }.permitted? + assert_predicate @params.select { |k| k == "person" }, :permitted? end test "select retains unpermitted status" do - assert_not @params.select { |k| k == "person" }.permitted? + assert_not_predicate @params.select { |k| k == "person" }, :permitted? end test "slice retains permitted status" do @params.permit! - assert @params.slice(:person).permitted? + assert_predicate @params.slice(:person), :permitted? end test "slice retains unpermitted status" do - assert_not @params.slice(:person).permitted? + assert_not_predicate @params.slice(:person), :permitted? end test "transform_keys retains permitted status" do @params.permit! - assert @params.transform_keys { |k| k }.permitted? + assert_predicate @params.transform_keys { |k| k }, :permitted? end test "transform_keys retains unpermitted status" do - assert_not @params.transform_keys { |k| k }.permitted? + assert_not_predicate @params.transform_keys { |k| k }, :permitted? end test "transform_values retains permitted status" do @params.permit! - assert @params.transform_values { |v| v }.permitted? + assert_predicate @params.transform_values { |v| v }, :permitted? end test "transform_values retains unpermitted status" do - assert_not @params.transform_values { |v| v }.permitted? + assert_not_predicate @params.transform_values { |v| v }, :permitted? end test "value? returns true if the given value is present in the params" do @@ -198,7 +197,7 @@ class ParametersAccessorsTest < ActiveSupport::TestCase 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") + assert_not params.value?("New York") end test "values returns an array of the values of the params" do @@ -208,13 +207,13 @@ class ParametersAccessorsTest < ActiveSupport::TestCase test "values_at retains permitted status" do @params.permit! - assert @params.values_at(:person).first.permitted? - assert @params[:person].values_at(:name).first.permitted? + assert_predicate @params.values_at(:person).first, :permitted? + assert_predicate @params[:person].values_at(:name).first, :permitted? end test "values_at retains unpermitted status" do - assert_not @params.values_at(:person).first.permitted? - assert_not @params[:person].values_at(:name).first.permitted? + assert_not_predicate @params.values_at(:person).first, :permitted? + assert_not_predicate @params[:person].values_at(:name).first, :permitted? end test "is equal to Parameters instance with same params" do @@ -273,23 +272,16 @@ class ParametersAccessorsTest < ActiveSupport::TestCase assert_match(/permitted: true/, @params.inspect) end - if Hash.method_defined?(:dig) - test "#dig delegates the dig method to its values" do - assert_equal "David", @params.dig(:person, :name, :first) - assert_equal "Chicago", @params.dig(:person, :addresses, 0, :city) - end + test "#dig delegates the dig method to its values" do + assert_equal "David", @params.dig(:person, :name, :first) + assert_equal "Chicago", @params.dig(:person, :addresses, 0, :city) + end - test "#dig converts hashes to parameters" do - assert_kind_of ActionController::Parameters, @params.dig(:person) - assert_kind_of ActionController::Parameters, @params.dig(:person, :addresses, 0) - assert @params.dig(:person, :addresses).all? do |value| - value.is_a?(ActionController::Parameters) - end - end - else - test "ActionController::Parameters does not respond to #dig on Ruby 2.2" do - assert_not ActionController::Parameters.method_defined?(:dig) - assert_not @params.respond_to?(:dig) + test "#dig converts hashes to parameters" do + assert_kind_of ActionController::Parameters, @params.dig(:person) + assert_kind_of ActionController::Parameters, @params.dig(:person, :addresses, 0) + assert @params.dig(:person, :addresses).all? do |value| + value.is_a?(ActionController::Parameters) end end end diff --git a/actionpack/test/controller/parameters/always_permitted_parameters_test.rb b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb index 1e8b71d789..fe0e5e368d 100644 --- a/actionpack/test/controller/parameters/always_permitted_parameters_test.rb +++ b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb @@ -25,6 +25,6 @@ class AlwaysPermittedParametersTest < ActiveSupport::TestCase book: { pages: 65 }, format: "json") permitted = params.permit book: [:pages] - assert permitted.permitted? + assert_predicate permitted, :permitted? end end diff --git a/actionpack/test/controller/parameters/dup_test.rb b/actionpack/test/controller/parameters/dup_test.rb index f5833aff46..5403fc6d93 100644 --- a/actionpack/test/controller/parameters/dup_test.rb +++ b/actionpack/test/controller/parameters/dup_test.rb @@ -23,7 +23,7 @@ class ParametersDupTest < ActiveSupport::TestCase test "a duplicate maintains the original's permitted status" do @params.permit! dupped_params = @params.dup - assert dupped_params.permitted? + assert_predicate dupped_params, :permitted? end test "a duplicate maintains the original's parameters" do @@ -57,11 +57,11 @@ class ParametersDupTest < ActiveSupport::TestCase dupped_params = @params.deep_dup dupped_params.permit! - assert_not @params.permitted? + assert_not_predicate @params, :permitted? end test "deep_dup @permitted is being copied" do @params.permit! - assert @params.deep_dup.permitted? + assert_predicate @params.deep_dup, :permitted? end end diff --git a/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb b/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb index dcf848a620..c890839727 100644 --- a/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb +++ b/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb @@ -21,7 +21,7 @@ class MultiParameterAttributesTest < ActiveSupport::TestCase permitted = params.permit book: [ :shipped_at, :price ] - assert permitted.permitted? + assert_predicate permitted, :permitted? assert_equal "2012", permitted[:book]["shipped_at(1i)"] assert_equal "3", permitted[:book]["shipped_at(2i)"] diff --git a/actionpack/test/controller/parameters/mutators_test.rb b/actionpack/test/controller/parameters/mutators_test.rb index 49dede03c2..312b1e5b27 100644 --- a/actionpack/test/controller/parameters/mutators_test.rb +++ b/actionpack/test/controller/parameters/mutators_test.rb @@ -2,7 +2,6 @@ require "abstract_unit" require "action_controller/metal/strong_parameters" -require "active_support/core_ext/hash/transform_values" class ParametersMutatorsTest < ActiveSupport::TestCase setup do @@ -20,11 +19,11 @@ class ParametersMutatorsTest < ActiveSupport::TestCase test "delete retains permitted status" do @params.permit! - assert @params.delete(:person).permitted? + assert_predicate @params.delete(:person), :permitted? end test "delete retains unpermitted status" do - assert_not @params.delete(:person).permitted? + assert_not_predicate @params.delete(:person), :permitted? end test "delete returns the value when the key is present" do @@ -50,73 +49,73 @@ class ParametersMutatorsTest < ActiveSupport::TestCase test "delete_if retains permitted status" do @params.permit! - assert @params.delete_if { |k| k == "person" }.permitted? + assert_predicate @params.delete_if { |k| k == "person" }, :permitted? end test "delete_if retains unpermitted status" do - assert_not @params.delete_if { |k| k == "person" }.permitted? + assert_not_predicate @params.delete_if { |k| k == "person" }, :permitted? end test "extract! retains permitted status" do @params.permit! - assert @params.extract!(:person).permitted? + assert_predicate @params.extract!(:person), :permitted? end test "extract! retains unpermitted status" do - assert_not @params.extract!(:person).permitted? + assert_not_predicate @params.extract!(:person), :permitted? end test "keep_if retains permitted status" do @params.permit! - assert @params.keep_if { |k, v| k == "person" }.permitted? + assert_predicate @params.keep_if { |k, v| k == "person" }, :permitted? end test "keep_if retains unpermitted status" do - assert_not @params.keep_if { |k, v| k == "person" }.permitted? + assert_not_predicate @params.keep_if { |k, v| k == "person" }, :permitted? end test "reject! retains permitted status" do @params.permit! - assert @params.reject! { |k| k == "person" }.permitted? + assert_predicate @params.reject! { |k| k == "person" }, :permitted? end test "reject! retains unpermitted status" do - assert_not @params.reject! { |k| k == "person" }.permitted? + assert_not_predicate @params.reject! { |k| k == "person" }, :permitted? end test "select! retains permitted status" do @params.permit! - assert @params.select! { |k| k != "person" }.permitted? + assert_predicate @params.select! { |k| k != "person" }, :permitted? end test "select! retains unpermitted status" do - assert_not @params.select! { |k| k != "person" }.permitted? + assert_not_predicate @params.select! { |k| k != "person" }, :permitted? end test "slice! retains permitted status" do @params.permit! - assert @params.slice!(:person).permitted? + assert_predicate @params.slice!(:person), :permitted? end test "slice! retains unpermitted status" do - assert_not @params.slice!(:person).permitted? + assert_not_predicate @params.slice!(:person), :permitted? end test "transform_keys! retains permitted status" do @params.permit! - assert @params.transform_keys! { |k| k }.permitted? + assert_predicate @params.transform_keys! { |k| k }, :permitted? end test "transform_keys! retains unpermitted status" do - assert_not @params.transform_keys! { |k| k }.permitted? + assert_not_predicate @params.transform_keys! { |k| k }, :permitted? end test "transform_values! retains permitted status" do @params.permit! - assert @params.transform_values! { |v| v }.permitted? + assert_predicate @params.transform_values! { |v| v }, :permitted? end test "transform_values! retains unpermitted status" do - assert_not @params.transform_values! { |v| v }.permitted? + assert_not_predicate @params.transform_values! { |v| v }, :permitted? end end diff --git a/actionpack/test/controller/parameters/nested_parameters_permit_test.rb b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb index c9fcc483ee..ccc6bf9807 100644 --- a/actionpack/test/controller/parameters/nested_parameters_permit_test.rb +++ b/actionpack/test/controller/parameters/nested_parameters_permit_test.rb @@ -32,7 +32,7 @@ class NestedParametersPermitTest < ActiveSupport::TestCase permitted = params.permit book: [ :title, { authors: [ :name ] }, { details: :pages }, :id ] - assert permitted.permitted? + assert_predicate permitted, :permitted? assert_equal "Romeo and Juliet", permitted[:book][:title] assert_equal "William Shakespeare", permitted[:book][:authors][0][:name] assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name] diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb index e9b94b056b..295f3a03ef 100644 --- a/actionpack/test/controller/parameters/parameters_permit_test.rb +++ b/actionpack/test/controller/parameters/parameters_permit_test.rb @@ -53,8 +53,8 @@ class ParametersPermitTest < ActiveSupport::TestCase test "if nothing is permitted, the hash becomes empty" do params = ActionController::Parameters.new(id: "1234") permitted = params.permit - assert permitted.permitted? - assert permitted.empty? + assert_predicate permitted, :permitted? + assert_empty permitted end test "key: permitted scalar values" do @@ -227,7 +227,7 @@ class ParametersPermitTest < ActiveSupport::TestCase test "hashes in array values get wrapped" do params = ActionController::Parameters.new(foo: [{}, {}]) params[:foo].each do |hash| - assert !hash.permitted? + assert_not_predicate hash, :permitted? end end @@ -250,7 +250,7 @@ class ParametersPermitTest < ActiveSupport::TestCase permitted = params.permit(users: [:id]) permitted[:users] << { injected: 1 } - assert_not permitted[:users].last.permitted? + assert_not_predicate permitted[:users].last, :permitted? end test "fetch doesnt raise ParameterMissing exception if there is a default" do @@ -272,12 +272,12 @@ class ParametersPermitTest < ActiveSupport::TestCase end test "not permitted is sticky beyond merges" do - assert !@params.merge(a: "b").permitted? + assert_not_predicate @params.merge(a: "b"), :permitted? end test "permitted is sticky beyond merges" do @params.permit! - assert @params.merge(a: "b").permitted? + assert_predicate @params.merge(a: "b"), :permitted? end test "merge with parameters" do @@ -288,12 +288,12 @@ class ParametersPermitTest < ActiveSupport::TestCase end test "not permitted is sticky beyond merge!" do - assert_not @params.merge!(a: "b").permitted? + assert_not_predicate @params.merge!(a: "b"), :permitted? end test "permitted is sticky beyond merge!" do @params.permit! - assert @params.merge!(a: "b").permitted? + assert_predicate @params.merge!(a: "b"), :permitted? end test "merge! with parameters" do @@ -355,10 +355,10 @@ class ParametersPermitTest < ActiveSupport::TestCase test "permit is recursive" do @params.permit! - assert @params.permitted? - assert @params[:person].permitted? - assert @params[:person][:name].permitted? - assert @params[:person][:addresses][0].permitted? + assert_predicate @params, :permitted? + assert_predicate @params[:person], :permitted? + assert_predicate @params[:person][:name], :permitted? + assert_predicate @params[:person][:addresses][0], :permitted? end test "permitted takes a default value when Parameters.permit_all_parameters is set" do @@ -368,8 +368,8 @@ class ParametersPermitTest < ActiveSupport::TestCase age: "32", name: { first: "David", last: "Heinemeier Hansson" } }) - assert params.slice(:person).permitted? - assert params[:person][:name].permitted? + assert_predicate params.slice(:person), :permitted? + assert_predicate params[:person][:name], :permitted? ensure ActionController::Parameters.permit_all_parameters = false end @@ -500,9 +500,9 @@ class ParametersPermitTest < ActiveSupport::TestCase params = ActionController::Parameters.new(foo: "bar") assert params.permit(:foo).has_key?(:foo) - refute params.permit(foo: []).has_key?(:foo) - refute params.permit(foo: [:bar]).has_key?(:foo) - refute params.permit(foo: :bar).has_key?(:foo) + assert_not params.permit(foo: []).has_key?(:foo) + assert_not params.permit(foo: [:bar]).has_key?(:foo) + assert_not params.permit(foo: :bar).has_key?(:foo) end test "#permitted? is false by default" do diff --git a/actionpack/test/controller/parameters/serialization_test.rb b/actionpack/test/controller/parameters/serialization_test.rb index 823f01d82a..7708c8e4fe 100644 --- a/actionpack/test/controller/parameters/serialization_test.rb +++ b/actionpack/test/controller/parameters/serialization_test.rb @@ -2,7 +2,6 @@ require "abstract_unit" require "action_controller/metal/strong_parameters" -require "active_support/core_ext/string/strip" class ParametersSerializationTest < ActiveSupport::TestCase setup do @@ -27,21 +26,21 @@ class ParametersSerializationTest < ActiveSupport::TestCase roundtripped = YAML.load(YAML.dump(params)) assert_equal params, roundtripped - assert_not roundtripped.permitted? + assert_not_predicate roundtripped, :permitted? end test "yaml backwardscompatible with psych 2.0.8 format" do - params = YAML.load <<-end_of_yaml.strip_heredoc + params = YAML.load <<~end_of_yaml --- !ruby/hash:ActionController::Parameters key: :value end_of_yaml assert_equal :value, params[:key] - assert_not params.permitted? + assert_not_predicate params, :permitted? end test "yaml backwardscompatible with psych 2.0.9+ format" do - params = YAML.load(<<-end_of_yaml.strip_heredoc) + params = YAML.load(<<~end_of_yaml) --- !ruby/hash-with-ivars:ActionController::Parameters elements: key: :value @@ -50,6 +49,6 @@ class ParametersSerializationTest < ActiveSupport::TestCase end_of_yaml assert_equal :value, params[:key] - assert_not params.permitted? + assert_not_predicate params, :permitted? end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 7c5101f993..fc21543049 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -415,7 +415,7 @@ class LastModifiedRenderTest < ActionController::TestCase @request.if_modified_since = @last_modified get :conditional_hello assert_equal 304, @response.status.to_i - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal @last_modified, @response.headers["Last-Modified"] end @@ -430,7 +430,7 @@ class LastModifiedRenderTest < ActionController::TestCase @request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT" get :conditional_hello assert_equal 200, @response.status.to_i - assert @response.body.present? + assert_predicate @response.body, :present? assert_equal @last_modified, @response.headers["Last-Modified"] end @@ -443,7 +443,7 @@ class LastModifiedRenderTest < ActionController::TestCase @request.if_modified_since = @last_modified get :conditional_hello_with_record assert_equal 304, @response.status.to_i - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_not_nil @response.etag assert_equal @last_modified, @response.headers["Last-Modified"] end @@ -459,7 +459,7 @@ class LastModifiedRenderTest < ActionController::TestCase @request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT" get :conditional_hello_with_record assert_equal 200, @response.status.to_i - assert @response.body.present? + assert_predicate @response.body, :present? assert_equal @last_modified, @response.headers["Last-Modified"] end @@ -472,7 +472,7 @@ class LastModifiedRenderTest < ActionController::TestCase @request.if_modified_since = @last_modified get :conditional_hello_with_collection_of_records assert_equal 304, @response.status.to_i - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal @last_modified, @response.headers["Last-Modified"] end @@ -487,7 +487,7 @@ class LastModifiedRenderTest < ActionController::TestCase @request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT" get :conditional_hello_with_collection_of_records assert_equal 200, @response.status.to_i - assert @response.body.present? + assert_predicate @response.body, :present? assert_equal @last_modified, @response.headers["Last-Modified"] end @@ -682,27 +682,27 @@ class HeadRenderTest < ActionController::TestCase def test_head_created post :head_created - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_response :created end def test_head_created_with_application_json_content_type post :head_created_with_application_json_content_type - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal "application/json", @response.header["Content-Type"] assert_response :created end def test_head_ok_with_image_png_content_type post :head_ok_with_image_png_content_type - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal "image/png", @response.header["Content-Type"] assert_response :ok end def test_head_with_location_header get :head_with_location_header - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal "/foo", @response.headers["Location"] assert_response :ok end @@ -718,7 +718,7 @@ class HeadRenderTest < ActionController::TestCase end get :head_with_location_object - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"] assert_response :ok end @@ -726,14 +726,14 @@ class HeadRenderTest < ActionController::TestCase def test_head_with_custom_header get :head_with_custom_header - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal "something", @response.headers["X-Custom-Header"] assert_response :ok end def test_head_with_www_authenticate_header get :head_with_www_authenticate_header - assert @response.body.blank? + assert_predicate @response.body, :blank? assert_equal "something", @response.headers["WWW-Authenticate"] assert_response :ok end @@ -812,7 +812,7 @@ class HttpCacheForeverTest < ActionController::TestCase assert_response :ok assert_equal "max-age=#{100.years}, public", @response.headers["Cache-Control"] assert_not_nil @response.etag - assert @response.weak_etag? + assert_predicate @response, :weak_etag? end def test_cache_with_private @@ -820,7 +820,7 @@ class HttpCacheForeverTest < ActionController::TestCase assert_response :ok assert_equal "max-age=#{100.years}, private", @response.headers["Cache-Control"] assert_not_nil @response.etag - assert @response.weak_etag? + assert_predicate @response, :weak_etag? end def test_cache_response_code_with_if_modified_since diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index 4822d85bcb..7a02c27c99 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -746,7 +746,7 @@ class FreeCookieControllerTest < ActionController::TestCase test "should not emit a csrf-token meta tag" do SecureRandom.stub :base64, @token do get :meta - assert @response.body.blank? + assert_predicate @response.body, :blank? end end end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index ec939e946a..9c0e101f7c 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -676,7 +676,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase 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) + escaped_token = CGI.escape(token) assert_equal "/page/" + escaped_token, url_for(rs, controller: "content", action: "show_page", id: token) assert_equal({ controller: "content", action: "show_page", id: token }, rs.recognize_path("/page/#{escaped_token}")) diff --git a/actionpack/test/controller/runner_test.rb b/actionpack/test/controller/runner_test.rb index a96c9c519b..1709ab5f6d 100644 --- a/actionpack/test/controller/runner_test.rb +++ b/actionpack/test/controller/runner_test.rb @@ -17,8 +17,8 @@ module ActionDispatch def test_respond_to? runner = MyRunner.new(Class.new { def x; end }.new) - assert runner.respond_to?(:hi) - assert runner.respond_to?(:x) + assert_respond_to runner, :hi + assert_respond_to runner, :x end end end diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index 536c5ed97a..7d4850294d 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -670,7 +670,7 @@ XML assert_equal "bar", @request.params[:foo] post :no_op - assert @request.params[:foo].blank? + assert_predicate @request.params[:foo], :blank? end def test_filtered_parameters_reset_between_requests @@ -838,7 +838,7 @@ XML def test_fixture_file_upload_should_be_able_access_to_tempfile file = fixture_file_upload(FILES_DIR + "/ruby_on_rails.jpg", "image/jpg") - assert file.respond_to?(:tempfile), "expected tempfile should respond on fixture file object, got nothing" + assert_respond_to file, :tempfile end def test_fixture_file_upload diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index cf11227897..e381abee36 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -288,7 +288,7 @@ module AbstractController kls = Class.new { include set.url_helpers } controller = kls.new - assert controller.respond_to?(:home_url) + assert_respond_to controller, :home_url assert_equal "http://www.basecamphq.com/home/sweet/home/again", controller.send(:home_url, host: "www.basecamphq.com", user: "again") diff --git a/actionpack/test/dispatch/content_security_policy_test.rb b/actionpack/test/dispatch/content_security_policy_test.rb index 7c4a65a633..b88f90190a 100644 --- a/actionpack/test/dispatch/content_security_policy_test.rb +++ b/actionpack/test/dispatch/content_security_policy_test.rb @@ -8,10 +8,10 @@ class ContentSecurityPolicyTest < ActiveSupport::TestCase end def test_build - assert_equal ";", @policy.build + assert_equal "", @policy.build @policy.script_src :self - assert_equal "script-src 'self';", @policy.build + assert_equal "script-src 'self'", @policy.build end def test_dup @@ -25,34 +25,34 @@ class ContentSecurityPolicyTest < ActiveSupport::TestCase def test_mappings @policy.script_src :data - assert_equal "script-src data:;", @policy.build + assert_equal "script-src data:", @policy.build @policy.script_src :mediastream - assert_equal "script-src mediastream:;", @policy.build + assert_equal "script-src mediastream:", @policy.build @policy.script_src :blob - assert_equal "script-src blob:;", @policy.build + assert_equal "script-src blob:", @policy.build @policy.script_src :filesystem - assert_equal "script-src filesystem:;", @policy.build + assert_equal "script-src filesystem:", @policy.build @policy.script_src :self - assert_equal "script-src 'self';", @policy.build + assert_equal "script-src 'self'", @policy.build @policy.script_src :unsafe_inline - assert_equal "script-src 'unsafe-inline';", @policy.build + assert_equal "script-src 'unsafe-inline'", @policy.build @policy.script_src :unsafe_eval - assert_equal "script-src 'unsafe-eval';", @policy.build + assert_equal "script-src 'unsafe-eval'", @policy.build @policy.script_src :none - assert_equal "script-src 'none';", @policy.build + assert_equal "script-src 'none'", @policy.build @policy.script_src :strict_dynamic - assert_equal "script-src 'strict-dynamic';", @policy.build + assert_equal "script-src 'strict-dynamic'", @policy.build @policy.script_src :none, :report_sample - assert_equal "script-src 'none' 'report-sample';", @policy.build + assert_equal "script-src 'none' 'report-sample'", @policy.build end def test_fetch_directives @@ -131,16 +131,16 @@ class ContentSecurityPolicyTest < ActiveSupport::TestCase def test_document_directives @policy.base_uri "https://example.com" - assert_match %r{base-uri https://example\.com;}, @policy.build + assert_match %r{base-uri https://example\.com}, @policy.build @policy.plugin_types "application/x-shockwave-flash" - assert_match %r{plugin-types application/x-shockwave-flash;}, @policy.build + assert_match %r{plugin-types application/x-shockwave-flash}, @policy.build @policy.sandbox - assert_match %r{sandbox;}, @policy.build + assert_match %r{sandbox}, @policy.build @policy.sandbox "allow-scripts", "allow-modals" - assert_match %r{sandbox allow-scripts allow-modals;}, @policy.build + assert_match %r{sandbox allow-scripts allow-modals}, @policy.build @policy.sandbox false assert_no_match %r{sandbox}, @policy.build @@ -148,35 +148,35 @@ class ContentSecurityPolicyTest < ActiveSupport::TestCase def test_navigation_directives @policy.form_action :self - assert_match %r{form-action 'self';}, @policy.build + assert_match %r{form-action 'self'}, @policy.build @policy.frame_ancestors :self - assert_match %r{frame-ancestors 'self';}, @policy.build + assert_match %r{frame-ancestors 'self'}, @policy.build end def test_reporting_directives @policy.report_uri "/violations" - assert_match %r{report-uri /violations;}, @policy.build + assert_match %r{report-uri /violations}, @policy.build end def test_other_directives @policy.block_all_mixed_content - assert_match %r{block-all-mixed-content;}, @policy.build + assert_match %r{block-all-mixed-content}, @policy.build @policy.block_all_mixed_content false assert_no_match %r{block-all-mixed-content}, @policy.build @policy.require_sri_for :script, :style - assert_match %r{require-sri-for script style;}, @policy.build + assert_match %r{require-sri-for script style}, @policy.build @policy.require_sri_for "script", "style" - assert_match %r{require-sri-for script style;}, @policy.build + assert_match %r{require-sri-for script style}, @policy.build @policy.require_sri_for assert_no_match %r{require-sri-for}, @policy.build @policy.upgrade_insecure_requests - assert_match %r{upgrade-insecure-requests;}, @policy.build + assert_match %r{upgrade-insecure-requests}, @policy.build @policy.upgrade_insecure_requests false assert_no_match %r{upgrade-insecure-requests}, @policy.build @@ -184,13 +184,13 @@ class ContentSecurityPolicyTest < ActiveSupport::TestCase def test_multiple_sources @policy.script_src :self, :https - assert_equal "script-src 'self' https:;", @policy.build + assert_equal "script-src 'self' https:", @policy.build end def test_multiple_directives @policy.script_src :self, :https @policy.style_src :self, :https - assert_equal "script-src 'self' https:; style-src 'self' https:;", @policy.build + assert_equal "script-src 'self' https:; style-src 'self' https:", @policy.build end def test_dynamic_directives @@ -198,12 +198,12 @@ class ContentSecurityPolicyTest < ActiveSupport::TestCase controller = Struct.new(:request).new(request) @policy.script_src -> { request.host } - assert_equal "script-src www.example.com;", @policy.build(controller) + assert_equal "script-src www.example.com", @policy.build(controller) end def test_mixed_static_and_dynamic_directives @policy.script_src :self, -> { "foo.com" }, "bar.com" - assert_equal "script-src 'self' foo.com bar.com;", @policy.build(Object.new) + assert_equal "script-src 'self' foo.com bar.com", @policy.build(Object.new) end def test_invalid_directive_source @@ -253,6 +253,11 @@ class ContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest p.report_uri "/violations" end + content_security_policy only: :script_src do |p| + p.default_src false + p.script_src :self + end + content_security_policy_report_only only: :report_only def index @@ -271,6 +276,10 @@ class ContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest head :ok end + def script_src + head :ok + end + private def condition? params[:condition] == "true" @@ -284,6 +293,7 @@ class ContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest get "/inline", to: "policy#inline" get "/conditional", to: "policy#conditional" get "/report-only", to: "policy#report_only" + get "/script-src", to: "policy#script_src" end end @@ -298,6 +308,7 @@ class ContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest def call(env) env["action_dispatch.content_security_policy"] = POLICY + env["action_dispatch.content_security_policy_nonce_generator"] = proc { "iyhD0Yc0W+c=" } env["action_dispatch.content_security_policy_report_only"] = false env["action_dispatch.show_exceptions"] = false @@ -316,25 +327,30 @@ class ContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest def test_generates_content_security_policy_header get "/" - assert_policy "default-src 'self';" + assert_policy "default-src 'self'" end def test_generates_inline_content_security_policy get "/inline" - assert_policy "default-src https://example.com;" + assert_policy "default-src https://example.com" end def test_generates_conditional_content_security_policy get "/conditional", params: { condition: "true" } - assert_policy "default-src https://true.example.com;" + assert_policy "default-src https://true.example.com" get "/conditional", params: { condition: "false" } - assert_policy "default-src https://false.example.com;" + assert_policy "default-src https://false.example.com" end def test_generates_report_only_content_security_policy get "/report-only" - assert_policy "default-src 'self'; report-uri /violations;", report_only: true + assert_policy "default-src 'self'; report-uri /violations", report_only: true + end + + def test_adds_nonce_to_script_src_content_security_policy + get "/script-src" + assert_policy "script-src 'self' 'nonce-iyhD0Yc0W+c='" end private diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index 40cbad3b0d..94cff10fe4 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -36,6 +36,12 @@ class CookieJarTest < ActiveSupport::TestCase assert_equal "bar", request.cookie_jar.fetch(:foo) end + def test_to_hash + request.cookie_jar["foo"] = "bar" + assert_equal({ "foo" => "bar" }, request.cookie_jar.to_hash) + assert_equal({ "foo" => "bar" }, request.cookie_jar.to_h) + end + def test_fetch_type_error assert_raises(KeyError) do request.cookie_jar.fetch(:omglolwut) @@ -319,7 +325,7 @@ class CookiesTest < ActionController::TestCase def test_setting_the_same_value_to_cookie request.cookies[:user_name] = "david" get :authenticate - assert_predicate response.cookies, :empty? + assert_empty response.cookies end def test_setting_the_same_value_to_permanent_cookie @@ -401,7 +407,7 @@ class CookiesTest < ActionController::TestCase def test_delete_unexisting_cookie request.cookies.clear get :delete_cookie - assert_predicate @response.cookies, :empty? + assert_empty @response.cookies end def test_deleted_cookie_predicate diff --git a/actionpack/test/dispatch/live_response_test.rb b/actionpack/test/dispatch/live_response_test.rb index 2901148a9e..a9a56f205f 100644 --- a/actionpack/test/dispatch/live_response_test.rb +++ b/actionpack/test/dispatch/live_response_test.rb @@ -73,7 +73,7 @@ module ActionController } latch.wait - assert @response.headers.frozen? + assert_predicate @response.headers, :frozen? e = assert_raises(ActionDispatch::IllegalStateError) do @response.headers["Content-Length"] = "zomg" end diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 6854783386..6167ea46df 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -159,7 +159,7 @@ class MimeTypeTest < ActiveSupport::TestCase types.each do |type| mime = Mime[type] - assert mime.respond_to?("#{type}?"), "#{mime.inspect} does not respond to #{type}?" + assert_respond_to mime, "#{type}?" assert_equal type, mime.symbol, "#{mime.inspect} is not #{type}?" invalid_types = types - [type] invalid_types.delete(:html) diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb index 7b6ce31f29..bf5a74e694 100644 --- a/actionpack/test/dispatch/request/session_test.rb +++ b/actionpack/test/dispatch/request/session_test.rb @@ -22,6 +22,7 @@ module ActionDispatch s["foo"] = "bar" assert_equal "bar", s["foo"] assert_equal({ "foo" => "bar" }, s.to_hash) + assert_equal({ "foo" => "bar" }, s.to_h) end def test_create_merges_old diff --git a/actionpack/test/dispatch/request_id_test.rb b/actionpack/test/dispatch/request_id_test.rb index aa3175c986..9df4712dab 100644 --- a/actionpack/test/dispatch/request_id_test.rb +++ b/actionpack/test/dispatch/request_id_test.rb @@ -11,6 +11,11 @@ class RequestIdTest < ActiveSupport::TestCase assert_equal "X-Hacked-HeaderStuff", stub_request("HTTP_X_REQUEST_ID" => "; X-Hacked-Header: Stuff").request_id end + test "accept Apache mod_unique_id format" do + mod_unique_id = "abcxyz@ABCXYZ-0123456789" + assert_equal mod_unique_id, stub_request("HTTP_X_REQUEST_ID" => mod_unique_id).request_id + end + test "ensure that 255 char limit on the request id is being enforced" do assert_equal "X" * 255, stub_request("HTTP_X_REQUEST_ID" => "X" * 500).request_id end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 66736e7722..84a2d1f69e 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -329,20 +329,20 @@ class RequestPort < BaseRequestTest test "standard_port?" do request = stub_request - assert !request.ssl? - assert request.standard_port? + assert_not_predicate request, :ssl? + assert_predicate request, :standard_port? request = stub_request "HTTPS" => "on" - assert request.ssl? - assert request.standard_port? + assert_predicate request, :ssl? + assert_predicate request, :standard_port? request = stub_request "HTTP_HOST" => "www.example.org:8080" - assert !request.ssl? - assert !request.standard_port? + assert_not_predicate request, :ssl? + assert_not_predicate request, :standard_port? request = stub_request "HTTP_HOST" => "www.example.org:8443", "HTTPS" => "on" - assert request.ssl? - assert !request.standard_port? + assert_predicate request, :ssl? + assert_not_predicate request, :standard_port? end test "optional port" do @@ -571,7 +571,7 @@ end class LocalhostTest < BaseRequestTest test "IPs that match localhost" do request = stub_request("REMOTE_IP" => "127.1.1.1", "REMOTE_ADDR" => "127.1.1.1") - assert request.local? + assert_predicate request, :local? end end @@ -643,37 +643,37 @@ class RequestProtocol < BaseRequestTest test "xml http request" do request = stub_request - assert !request.xml_http_request? - assert !request.xhr? + assert_not_predicate request, :xml_http_request? + assert_not_predicate request, :xhr? request = stub_request "HTTP_X_REQUESTED_WITH" => "DefinitelyNotAjax1.0" - assert !request.xml_http_request? - assert !request.xhr? + assert_not_predicate request, :xml_http_request? + assert_not_predicate request, :xhr? request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" - assert request.xml_http_request? - assert request.xhr? + assert_predicate request, :xml_http_request? + assert_predicate request, :xhr? end test "reports ssl" do - assert !stub_request.ssl? - assert stub_request("HTTPS" => "on").ssl? + assert_not_predicate stub_request, :ssl? + assert_predicate stub_request("HTTPS" => "on"), :ssl? end test "reports ssl when proxied via lighttpd" do - assert stub_request("HTTP_X_FORWARDED_PROTO" => "https").ssl? + assert_predicate stub_request("HTTP_X_FORWARDED_PROTO" => "https"), :ssl? end test "scheme returns https when proxied" do request = stub_request "rack.url_scheme" => "http" - assert !request.ssl? + assert_not_predicate request, :ssl? assert_equal "http", request.scheme request = stub_request( "rack.url_scheme" => "http", "HTTP_X_FORWARDED_PROTO" => "https" ) - assert request.ssl? + assert_predicate request, :ssl? assert_equal "https", request.scheme end end @@ -700,7 +700,7 @@ class RequestMethod < BaseRequestTest assert_equal "GET", request.request_method assert_equal "GET", request.env["REQUEST_METHOD"] - assert request.get? + assert_predicate request, :get? end test "invalid http method raises exception" do @@ -748,7 +748,7 @@ class RequestMethod < BaseRequestTest assert_equal "POST", request.method assert_equal "PATCH", request.request_method - assert request.patch? + assert_predicate request, :patch? end test "post masquerading as put" do @@ -758,7 +758,7 @@ class RequestMethod < BaseRequestTest ) assert_equal "POST", request.method assert_equal "PUT", request.request_method - assert request.put? + assert_predicate request, :put? end test "post uneffected by local inflections" do @@ -772,7 +772,7 @@ class RequestMethod < BaseRequestTest request = stub_request "REQUEST_METHOD" => "POST" assert_equal :post, ActionDispatch::Request::HTTP_METHOD_LOOKUP["POST"] assert_equal :post, request.method_symbol - assert request.post? + assert_predicate request, :post? ensure # Reset original acronym set ActiveSupport::Inflector.inflections do |inflect| @@ -809,20 +809,20 @@ class RequestFormat < BaseRequestTest "QUERY_STRING" => "" ) - assert request.xhr? + assert_predicate request, :xhr? assert_equal Mime[:js], request.format end test "can override format with parameter negative" do request = stub_request("QUERY_STRING" => "format=txt") - assert !request.format.xml? + assert_not_predicate request.format, :xml? end test "can override format with parameter positive" do request = stub_request("QUERY_STRING" => "format=xml") - assert request.format.xml? + assert_predicate request.format, :xml? end test "formats text/html with accept header" do @@ -862,15 +862,15 @@ class RequestFormat < BaseRequestTest request = stub_request("QUERY_STRING" => "format=hello") assert_nil request.format - assert_not request.format.html? - assert_not request.format.xml? - assert_not request.format.json? + assert_not_predicate request.format, :html? + assert_not_predicate request.format, :xml? + assert_not_predicate request.format, :json? end test "format does not throw exceptions when malformed parameters" do request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2") assert request.formats - assert request.format.html? + assert_predicate request.format, :html? end test "formats with xhr request" do @@ -1234,8 +1234,8 @@ class RequestVariant < BaseRequestTest test "setting variant to a symbol" do @request.variant = :phone - assert @request.variant.phone? - assert_not @request.variant.tablet? + assert_predicate @request.variant, :phone? + assert_not_predicate @request.variant, :tablet? assert @request.variant.any?(:phone, :tablet) assert_not @request.variant.any?(:tablet, :desktop) end @@ -1243,9 +1243,9 @@ class RequestVariant < BaseRequestTest test "setting variant to an array of symbols" do @request.variant = [:phone, :tablet] - assert @request.variant.phone? - assert @request.variant.tablet? - assert_not @request.variant.desktop? + assert_predicate @request.variant, :phone? + assert_predicate @request.variant, :tablet? + assert_not_predicate @request.variant, :desktop? assert @request.variant.any?(:tablet, :desktop) assert_not @request.variant.any?(:desktop, :watch) end @@ -1253,8 +1253,8 @@ class RequestVariant < BaseRequestTest test "clearing variant" do @request.variant = nil - assert @request.variant.empty? - assert_not @request.variant.phone? + assert_empty @request.variant + assert_not_predicate @request.variant, :phone? assert_not @request.variant.any?(:phone, :tablet) end @@ -1273,13 +1273,13 @@ end class RequestFormData < BaseRequestTest test "media_type is from the FORM_DATA_MEDIA_TYPES array" do - assert stub_request("CONTENT_TYPE" => "application/x-www-form-urlencoded").form_data? - assert stub_request("CONTENT_TYPE" => "multipart/form-data").form_data? + assert_predicate stub_request("CONTENT_TYPE" => "application/x-www-form-urlencoded"), :form_data? + assert_predicate stub_request("CONTENT_TYPE" => "multipart/form-data"), :form_data? end test "media_type is not from the FORM_DATA_MEDIA_TYPES array" do - assert !stub_request("CONTENT_TYPE" => "application/xml").form_data? - assert !stub_request("CONTENT_TYPE" => "multipart/related").form_data? + assert_not_predicate stub_request("CONTENT_TYPE" => "application/xml"), :form_data? + assert_not_predicate stub_request("CONTENT_TYPE" => "multipart/related"), :form_data? end test "no Content-Type header is provided and the request_method is POST" do @@ -1287,7 +1287,7 @@ class RequestFormData < BaseRequestTest assert_equal "", request.media_type assert_equal "POST", request.request_method - assert !request.form_data? + assert_not_predicate request, :form_data? end end diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb index 0b727dad3d..4c8d528507 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -15,13 +15,13 @@ class ResponseTest < ActiveSupport::TestCase @response.await_commit } @response.commit! - assert @response.committed? + assert_predicate @response, :committed? assert t.join(0.5) end def test_stream_close @response.stream.close - assert @response.stream.closed? + assert_predicate @response.stream, :closed? end def test_stream_write @@ -257,9 +257,9 @@ class ResponseTest < ActiveSupport::TestCase } resp.to_a - assert resp.etag? - assert resp.weak_etag? - assert_not resp.strong_etag? + assert_predicate resp, :etag? + assert_predicate resp, :weak_etag? + assert_not_predicate resp, :strong_etag? assert_equal('W/"202cb962ac59075b964b07152d234b70"', resp.etag) assert_equal({ public: true }, resp.cache_control) @@ -275,9 +275,9 @@ class ResponseTest < ActiveSupport::TestCase } resp.to_a - assert resp.etag? - assert_not resp.weak_etag? - assert resp.strong_etag? + assert_predicate resp, :etag? + assert_not_predicate resp, :weak_etag? + assert_predicate resp, :strong_etag? assert_equal('"202cb962ac59075b964b07152d234b70"', resp.etag) end @@ -356,7 +356,7 @@ class ResponseTest < ActiveSupport::TestCase end test "respond_to? accepts include_private" do - assert_not @response.respond_to?(:method_missing) + assert_not_respond_to @response, :method_missing assert @response.respond_to?(:method_missing, true) end diff --git a/actionpack/test/dispatch/routing_assertions_test.rb b/actionpack/test/dispatch/routing_assertions_test.rb index a5198f2f13..009b6d9bc3 100644 --- a/actionpack/test/dispatch/routing_assertions_test.rb +++ b/actionpack/test/dispatch/routing_assertions_test.rb @@ -52,6 +52,8 @@ class RoutingAssertionsTest < ActionController::TestCase end mount engine => "/shelf" + + get "/shelf/foo", controller: "query_articles", action: "index" end end @@ -154,6 +156,10 @@ class RoutingAssertionsTest < ActionController::TestCase assert_match err.message, "This is a really bad msg" end + def test_assert_recognizes_continue_to_recoginize_after_it_tried_engines + assert_recognizes({ controller: "query_articles", action: "index" }, "/shelf/foo") + end + def test_assert_routing assert_routing("/articles", controller: "articles", action: "index") end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 8f4e7c96a9..fe314e26b1 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -3313,7 +3313,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end get "/search" - assert !@request.params[:action].frozen? + assert_not_predicate @request.params[:action], :frozen? end def test_multiple_positional_args_with_the_same_name @@ -4267,7 +4267,7 @@ class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest def app; APP end test "enabled when not mounted and default_url_options is empty" do - assert Routes.url_helpers.optimize_routes_generation? + assert_predicate Routes.url_helpers, :optimize_routes_generation? end test "named route called as singleton method" do @@ -4500,7 +4500,7 @@ class TestPortConstraints < ActionDispatch::IntegrationTest get "/integer", to: ok, constraints: { port: 8080 } get "/string", to: ok, constraints: { port: "8080" } - get "/array", to: ok, constraints: { port: [8080] } + get "/array/:idx", to: ok, constraints: { port: [8080], idx: %w[first last] } get "/regexp", to: ok, constraints: { port: /8080/ } end end @@ -4529,7 +4529,10 @@ class TestPortConstraints < ActionDispatch::IntegrationTest get "http://www.example.com/array" assert_response :not_found - get "http://www.example.com:8080/array" + get "http://www.example.com:8080/array/middle" + assert_response :not_found + + get "http://www.example.com:8080/array/first" assert_response :success end diff --git a/actionpack/test/dispatch/system_testing/driver_test.rb b/actionpack/test/dispatch/system_testing/driver_test.rb index fcdaf7fb4c..a824ee0c84 100644 --- a/actionpack/test/dispatch/system_testing/driver_test.rb +++ b/actionpack/test/dispatch/system_testing/driver_test.rb @@ -12,7 +12,8 @@ class DriverTest < ActiveSupport::TestCase 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 :chrome, driver.instance_variable_get(:@browser).name + assert_nil driver.instance_variable_get(:@browser).options assert_equal [1400, 1400], driver.instance_variable_get(:@screen_size) assert_equal ({ url: "http://example.com/wd/hub" }), driver.instance_variable_get(:@options) end @@ -20,7 +21,7 @@ class DriverTest < ActiveSupport::TestCase test "initializing the driver with a headless chrome" do driver = ActionDispatch::SystemTesting::Driver.new(:selenium, using: :headless_chrome, screen_size: [1400, 1400], options: { url: "http://example.com/wd/hub" }) assert_equal :selenium, driver.instance_variable_get(:@name) - assert_equal :headless_chrome, driver.instance_variable_get(:@browser) + assert_equal :headless_chrome, driver.instance_variable_get(:@browser).name assert_equal [1400, 1400], driver.instance_variable_get(:@screen_size) assert_equal ({ url: "http://example.com/wd/hub" }), driver.instance_variable_get(:@options) end @@ -28,7 +29,7 @@ class DriverTest < ActiveSupport::TestCase test "initializing the driver with a headless firefox" do driver = ActionDispatch::SystemTesting::Driver.new(:selenium, using: :headless_firefox, screen_size: [1400, 1400], options: { url: "http://example.com/wd/hub" }) assert_equal :selenium, driver.instance_variable_get(:@name) - assert_equal :headless_firefox, driver.instance_variable_get(:@browser) + assert_equal :headless_firefox, driver.instance_variable_get(:@browser).name assert_equal [1400, 1400], driver.instance_variable_get(:@screen_size) assert_equal ({ url: "http://example.com/wd/hub" }), driver.instance_variable_get(:@options) end diff --git a/actionpack/test/dispatch/uploaded_file_test.rb b/actionpack/test/dispatch/uploaded_file_test.rb index 24c7135c7e..5a584b12e5 100644 --- a/actionpack/test/dispatch/uploaded_file_test.rb +++ b/actionpack/test/dispatch/uploaded_file_test.rb @@ -100,14 +100,14 @@ module ActionDispatch def test_delegate_eof_to_tempfile tf = Class.new { def eof?; true end; } uf = Http::UploadedFile.new(tempfile: tf.new) - assert uf.eof? + assert_predicate uf, :eof? end def test_respond_to? tf = Class.new { def read; yield end } uf = Http::UploadedFile.new(tempfile: tf.new) - assert uf.respond_to?(:headers), "responds to headers" - assert uf.respond_to?(:read), "responds to read" + assert_respond_to uf, :headers + assert_respond_to uf, :read end end end diff --git a/actionpack/test/journey/nodes/symbol_test.rb b/actionpack/test/journey/nodes/symbol_test.rb index 1e687acef2..b0622ac71a 100644 --- a/actionpack/test/journey/nodes/symbol_test.rb +++ b/actionpack/test/journey/nodes/symbol_test.rb @@ -8,10 +8,10 @@ module ActionDispatch class TestSymbol < ActiveSupport::TestCase def test_default_regexp? sym = Symbol.new "foo" - assert sym.default_regexp? + assert_predicate sym, :default_regexp? sym.regexp = nil - assert_not sym.default_regexp? + assert_not_predicate sym, :default_regexp? end end end diff --git a/actionpack/test/journey/routes_test.rb b/actionpack/test/journey/routes_test.rb index 81ce07526f..d5c81a8421 100644 --- a/actionpack/test/journey/routes_test.rb +++ b/actionpack/test/journey/routes_test.rb @@ -17,11 +17,11 @@ module ActionDispatch def test_clear mapper.get "/foo(/:id)", to: "foo#bar", as: "aaron" - assert_not_predicate routes, :empty? + assert_not_empty routes assert_equal 1, routes.length routes.clear - assert routes.empty? + assert_empty routes assert_equal 0, routes.length end @@ -43,7 +43,7 @@ module ActionDispatch mapper.get "/foo(/:id)", to: "foo#bar", as: "aaron" assert_equal 1, @routes.anchored_routes.length - assert_predicate @routes.custom_routes, :empty? + assert_empty @routes.custom_routes mapper.get "/hello/:who", to: "foo#bar", as: "bar", who: /\d/ diff --git a/actionpack/test/tmp/.gitignore b/actionpack/test/tmp/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/actionpack/test/tmp/.gitignore +++ /dev/null |