diff options
Diffstat (limited to 'actionpack/test')
40 files changed, 999 insertions, 501 deletions
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 46de36317e..6584d20840 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -251,7 +251,6 @@ end module ActionController class Base - include ActionController::Testing # This stub emulates the Railtie including the URL helpers from a Rails application include SharedTestRoutes.url_helpers include SharedTestRoutes.mounted_helpers diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb index 580604df3a..f07d201563 100644 --- a/actionpack/test/controller/assert_select_test.rb +++ b/actionpack/test/controller/assert_select_test.rb @@ -56,13 +56,16 @@ class AssertSelectTest < ActionController::TestCase def setup super + @old_delivery_method = ActionMailer::Base.delivery_method + @old_perform_deliveries = ActionMailer::Base.perform_deliveries ActionMailer::Base.delivery_method = :test ActionMailer::Base.perform_deliveries = true - ActionMailer::Base.deliveries = [] end def teardown super + ActionMailer::Base.delivery_method = @old_delivery_method + ActionMailer::Base.perform_deliveries = @old_perform_deliveries ActionMailer::Base.deliveries.clear end diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb index 03d5d27cf4..89667df3a4 100644 --- a/actionpack/test/controller/content_type_test.rb +++ b/actionpack/test/controller/content_type_test.rb @@ -68,12 +68,11 @@ class ContentTypeTest < ActionController::TestCase end def test_render_changed_charset_default - ActionDispatch::Response.default_charset = "utf-16" - get :render_defaults - assert_equal "utf-16", @response.charset - assert_equal Mime::HTML, @response.content_type - ensure - ActionDispatch::Response.default_charset = "utf-8" + with_default_charset "utf-16" do + get :render_defaults + assert_equal "utf-16", @response.charset + assert_equal Mime::HTML, @response.content_type + end end # :ported: @@ -105,12 +104,11 @@ class ContentTypeTest < ActionController::TestCase end def test_nil_default_for_erb - ActionDispatch::Response.default_charset = nil - get :render_default_for_erb - assert_equal Mime::HTML, @response.content_type - assert_nil @response.charset, @response.headers.inspect - ensure - ActionDispatch::Response.default_charset = "utf-8" + with_default_charset nil do + get :render_default_for_erb + assert_equal Mime::HTML, @response.content_type + assert_nil @response.charset, @response.headers.inspect + end end def test_default_for_erb @@ -130,6 +128,16 @@ class ContentTypeTest < ActionController::TestCase assert_equal Mime::HTML, @response.content_type assert_equal "utf-8", @response.charset end + + private + + def with_default_charset(charset) + old_default_charset = ActionDispatch::Response.default_charset + ActionDispatch::Response.default_charset = charset + yield + ensure + ActionDispatch::Response.default_charset = old_default_charset + end end class AcceptBasedContentTypeTest < ActionController::TestCase diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index c87494aa64..b2b01b3fa9 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -2,13 +2,13 @@ require 'abstract_unit' class ActionController::Base class << self - %w(append_around_filter prepend_after_filter prepend_around_filter prepend_before_filter skip_after_filter skip_before_filter skip_filter).each do |pending| + %w(append_around_action prepend_after_action prepend_around_action prepend_before_action skip_after_action skip_before_action skip_action_callback).each do |pending| define_method(pending) do |*args| $stderr.puts "#{pending} unimplemented: #{args.inspect}" end unless method_defined?(pending) end - def before_filters + def before_actions filters = _process_action_callbacks.select { |c| c.kind == :before } filters.map! { |c| c.raw_filter } end @@ -28,8 +28,8 @@ end class FilterTest < ActionController::TestCase class TestController < ActionController::Base - before_filter :ensure_login - after_filter :clean_up + before_action :ensure_login + after_action :clean_up def show render :inline => "ran action" @@ -42,13 +42,13 @@ class FilterTest < ActionController::TestCase end def clean_up - @ran_after_filter ||= [] - @ran_after_filter << "clean_up" + @ran_after_action ||= [] + @ran_after_action << "clean_up" end end class ChangingTheRequirementsController < TestController - before_filter :ensure_login, :except => [:go_wild] + before_action :ensure_login, :except => [:go_wild] def go_wild render :text => "gobble" @@ -56,9 +56,9 @@ class FilterTest < ActionController::TestCase end class TestMultipleFiltersController < ActionController::Base - before_filter :try_1 - before_filter :try_2 - before_filter :try_3 + before_action :try_1 + before_action :try_2 + before_action :try_3 (1..3).each do |i| define_method "fail_#{i}" do @@ -78,8 +78,8 @@ class FilterTest < ActionController::TestCase end class RenderingController < ActionController::Base - before_filter :before_filter_rendering - after_filter :unreached_after_filter + before_action :before_action_rendering + after_action :unreached_after_action def show @ran_action = true @@ -87,29 +87,29 @@ class FilterTest < ActionController::TestCase end private - def before_filter_rendering + def before_action_rendering @ran_filter ||= [] - @ran_filter << "before_filter_rendering" + @ran_filter << "before_action_rendering" render :inline => "something else" end - def unreached_after_filter - @ran_filter << "unreached_after_filter_after_render" + def unreached_after_action + @ran_filter << "unreached_after_action_after_render" end end - class RenderingForPrependAfterFilterController < RenderingController - prepend_after_filter :unreached_prepend_after_filter + class RenderingForPrependAfterActionController < RenderingController + prepend_after_action :unreached_prepend_after_action private - def unreached_prepend_after_filter - @ran_filter << "unreached_preprend_after_filter_after_render" + def unreached_prepend_after_action + @ran_filter << "unreached_preprend_after_action_after_render" end end - class BeforeFilterRedirectionController < ActionController::Base - before_filter :before_filter_redirects - after_filter :unreached_after_filter + class BeforeActionRedirectionController < ActionController::Base + before_action :before_action_redirects + after_action :unreached_after_action def show @ran_action = true @@ -122,23 +122,23 @@ class FilterTest < ActionController::TestCase end private - def before_filter_redirects + def before_action_redirects @ran_filter ||= [] - @ran_filter << "before_filter_redirects" + @ran_filter << "before_action_redirects" redirect_to(:action => 'target_of_redirection') end - def unreached_after_filter - @ran_filter << "unreached_after_filter_after_redirection" + def unreached_after_action + @ran_filter << "unreached_after_action_after_redirection" end end - class BeforeFilterRedirectionForPrependAfterFilterController < BeforeFilterRedirectionController - prepend_after_filter :unreached_prepend_after_filter_after_redirection + class BeforeActionRedirectionForPrependAfterActionController < BeforeActionRedirectionController + prepend_after_action :unreached_prepend_after_action_after_redirection private - def unreached_prepend_after_filter_after_redirection - @ran_filter << "unreached_prepend_after_filter_after_redirection" + def unreached_prepend_after_action_after_redirection + @ran_filter << "unreached_prepend_after_action_after_redirection" end end @@ -151,8 +151,8 @@ class FilterTest < ActionController::TestCase render :inline => "ran action" end - def show_without_filter - render :inline => "ran action without filter" + def show_without_action + render :inline => "ran action without action" end private @@ -168,70 +168,70 @@ class FilterTest < ActionController::TestCase end class ConditionalCollectionFilterController < ConditionalFilterController - before_filter :ensure_login, :except => [ :show_without_filter, :another_action ] + before_action :ensure_login, :except => [ :show_without_action, :another_action ] end class OnlyConditionSymController < ConditionalFilterController - before_filter :ensure_login, :only => :show + before_action :ensure_login, :only => :show end class ExceptConditionSymController < ConditionalFilterController - before_filter :ensure_login, :except => :show_without_filter + before_action :ensure_login, :except => :show_without_action end class BeforeAndAfterConditionController < ConditionalFilterController - before_filter :ensure_login, :only => :show - after_filter :clean_up_tmp, :only => :show + before_action :ensure_login, :only => :show + after_action :clean_up_tmp, :only => :show end class OnlyConditionProcController < ConditionalFilterController - before_filter(:only => :show) {|c| c.instance_variable_set(:"@ran_proc_filter", true) } + before_action(:only => :show) {|c| c.instance_variable_set(:"@ran_proc_action", true) } end class ExceptConditionProcController < ConditionalFilterController - before_filter(:except => :show_without_filter) {|c| c.instance_variable_set(:"@ran_proc_filter", true) } + before_action(:except => :show_without_action) {|c| c.instance_variable_set(:"@ran_proc_action", true) } end class ConditionalClassFilter - def self.before(controller) controller.instance_variable_set(:"@ran_class_filter", true) end + def self.before(controller) controller.instance_variable_set(:"@ran_class_action", true) end end class OnlyConditionClassController < ConditionalFilterController - before_filter ConditionalClassFilter, :only => :show + before_action ConditionalClassFilter, :only => :show end class ExceptConditionClassController < ConditionalFilterController - before_filter ConditionalClassFilter, :except => :show_without_filter + before_action ConditionalClassFilter, :except => :show_without_action end class AnomolousYetValidConditionController < ConditionalFilterController - before_filter(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.instance_variable_set(:"@ran_proc_filter1", true)}, :except => :show_without_filter) { |c| c.instance_variable_set(:"@ran_proc_filter2", true)} + before_action(ConditionalClassFilter, :ensure_login, Proc.new {|c| c.instance_variable_set(:"@ran_proc_action1", true)}, :except => :show_without_action) { |c| c.instance_variable_set(:"@ran_proc_action2", true)} end class OnlyConditionalOptionsFilter < ConditionalFilterController - before_filter :ensure_login, :only => :index, :if => Proc.new {|c| c.instance_variable_set(:"@ran_conditional_index_proc", true) } + before_action :ensure_login, :only => :index, :if => Proc.new {|c| c.instance_variable_set(:"@ran_conditional_index_proc", true) } end class ConditionalOptionsFilter < ConditionalFilterController - before_filter :ensure_login, :if => Proc.new { |c| true } - before_filter :clean_up_tmp, :if => Proc.new { |c| false } + before_action :ensure_login, :if => Proc.new { |c| true } + before_action :clean_up_tmp, :if => Proc.new { |c| false } end class ConditionalOptionsSkipFilter < ConditionalFilterController - before_filter :ensure_login - before_filter :clean_up_tmp + before_action :ensure_login + before_action :clean_up_tmp - skip_before_filter :ensure_login, if: -> { false } - skip_before_filter :clean_up_tmp, if: -> { true } + skip_before_action :ensure_login, if: -> { false } + skip_before_action :clean_up_tmp, if: -> { true } end class ClassController < ConditionalFilterController - before_filter ConditionalClassFilter + before_action ConditionalClassFilter end class PrependingController < TestController - prepend_before_filter :wonderful_life - # skip_before_filter :fire_flash + prepend_before_action :wonderful_life + # skip_before_action :fire_flash private def wonderful_life @@ -241,8 +241,8 @@ class FilterTest < ActionController::TestCase end class SkippingAndLimitedController < TestController - skip_before_filter :ensure_login - before_filter :ensure_login, :only => :index + skip_before_action :ensure_login + before_action :ensure_login, :only => :index def index render :text => 'ok' @@ -254,9 +254,9 @@ class FilterTest < ActionController::TestCase end class SkippingAndReorderingController < TestController - skip_before_filter :ensure_login - before_filter :find_record - before_filter :ensure_login + skip_before_action :ensure_login + before_action :find_record + before_action :ensure_login def index render :text => 'ok' @@ -270,10 +270,10 @@ class FilterTest < ActionController::TestCase end class ConditionalSkippingController < TestController - skip_before_filter :ensure_login, :only => [ :login ] - skip_after_filter :clean_up, :only => [ :login ] + skip_before_action :ensure_login, :only => [ :login ] + skip_after_action :clean_up, :only => [ :login ] - before_filter :find_user, :only => [ :change_password ] + before_action :find_user, :only => [ :change_password ] def login render :inline => "ran action" @@ -291,8 +291,8 @@ class FilterTest < ActionController::TestCase end class ConditionalParentOfConditionalSkippingController < ConditionalFilterController - before_filter :conditional_in_parent_before, :only => [:show, :another_action] - after_filter :conditional_in_parent_after, :only => [:show, :another_action] + before_action :conditional_in_parent_before, :only => [:show, :another_action] + after_action :conditional_in_parent_after, :only => [:show, :another_action] private @@ -308,20 +308,20 @@ class FilterTest < ActionController::TestCase end class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController - skip_before_filter :conditional_in_parent_before, :only => :another_action - skip_after_filter :conditional_in_parent_after, :only => :another_action + skip_before_action :conditional_in_parent_before, :only => :another_action + skip_after_action :conditional_in_parent_after, :only => :another_action end class AnotherChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController - skip_before_filter :conditional_in_parent_before, :only => :show + skip_before_action :conditional_in_parent_before, :only => :show end class ProcController < PrependingController - before_filter(proc { |c| c.instance_variable_set(:"@ran_proc_filter", true) }) + before_action(proc { |c| c.instance_variable_set(:"@ran_proc_action", true) }) end class ImplicitProcController < PrependingController - before_filter { |c| c.instance_variable_set(:"@ran_proc_filter", true) } + before_action { |c| c.instance_variable_set(:"@ran_proc_action", true) } end class AuditFilter @@ -367,7 +367,7 @@ class FilterTest < ActionController::TestCase end class AuditController < ActionController::Base - before_filter(AuditFilter) + before_action(AuditFilter) def show render :text => "hello" @@ -375,14 +375,14 @@ class FilterTest < ActionController::TestCase end class AroundFilterController < PrependingController - around_filter AroundFilter.new + around_action AroundFilter.new end class BeforeAfterClassFilterController < PrependingController begin filter = AroundFilter.new - before_filter filter - after_filter filter + before_action filter + after_action filter end end @@ -394,18 +394,18 @@ class FilterTest < ActionController::TestCase super() end - before_filter { |c| c.class.execution_log << " before procfilter " } - prepend_around_filter AroundFilter.new + before_action { |c| c.class.execution_log << " before procfilter " } + prepend_around_action AroundFilter.new - after_filter { |c| c.class.execution_log << " after procfilter " } - append_around_filter AppendedAroundFilter.new + after_action { |c| c.class.execution_log << " after procfilter " } + append_around_action AppendedAroundFilter.new end class MixedSpecializationController < ActionController::Base class OutOfOrder < StandardError; end - before_filter :first - before_filter :second, :only => :foo + before_action :first + before_action :second, :only => :foo def foo render :text => 'foo' @@ -426,7 +426,7 @@ class FilterTest < ActionController::TestCase end class DynamicDispatchController < ActionController::Base - before_filter :choose + before_action :choose %w(foo bar baz).each do |action| define_method(action) { render :text => action } @@ -439,9 +439,9 @@ class FilterTest < ActionController::TestCase end class PrependingBeforeAndAfterController < ActionController::Base - prepend_before_filter :before_all - prepend_after_filter :after_all - before_filter :between_before_all_and_after_all + prepend_before_action :before_all + prepend_after_action :after_all + before_action :between_before_all_and_after_all def before_all @ran_filter ||= [] @@ -473,7 +473,7 @@ class FilterTest < ActionController::TestCase end class RescuedController < ActionController::Base - around_filter RescuingAroundFilterWithBlock.new + around_action RescuingAroundFilterWithBlock.new def show raise ErrorToRescue.new("Something made the bad noise.") @@ -482,10 +482,10 @@ class FilterTest < ActionController::TestCase class NonYieldingAroundFilterController < ActionController::Base - before_filter :filter_one - around_filter :non_yielding_filter - before_filter :filter_two - after_filter :filter_three + before_action :filter_one + around_action :non_yielding_action + before_action :action_two + after_action :action_three def index render :inline => "index" @@ -498,24 +498,24 @@ class FilterTest < ActionController::TestCase @filters << "filter_one" end - def filter_two - @filters << "filter_two" + def action_two + @filters << "action_two" end - def non_yielding_filter + def non_yielding_action @filters << "it didn't yield" @filter_return_value end - def filter_three - @filters << "filter_three" + def action_three + @filters << "action_three" end end class ImplicitActionsController < ActionController::Base - before_filter :find_only, :only => :edit - before_filter :find_except, :except => :edit + before_action :find_only, :only => :edit + before_action :find_except, :except => :edit private @@ -528,7 +528,7 @@ class FilterTest < ActionController::TestCase end end - def test_non_yielding_around_filters_not_returning_false_do_not_raise + def test_non_yielding_around_actions_not_returning_false_do_not_raise controller = NonYieldingAroundFilterController.new controller.instance_variable_set "@filter_return_value", true assert_nothing_raised do @@ -536,7 +536,7 @@ class FilterTest < ActionController::TestCase end end - def test_non_yielding_around_filters_returning_false_do_not_raise + def test_non_yielding_around_actions_returning_false_do_not_raise controller = NonYieldingAroundFilterController.new controller.instance_variable_set "@filter_return_value", false assert_nothing_raised do @@ -544,64 +544,64 @@ class FilterTest < ActionController::TestCase end end - def test_after_filters_are_not_run_if_around_filter_returns_false + def test_after_actions_are_not_run_if_around_action_returns_false controller = NonYieldingAroundFilterController.new controller.instance_variable_set "@filter_return_value", false test_process(controller, "index") assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters'] end - def test_after_filters_are_not_run_if_around_filter_does_not_yield + def test_after_actions_are_not_run_if_around_action_does_not_yield controller = NonYieldingAroundFilterController.new controller.instance_variable_set "@filter_return_value", true test_process(controller, "index") assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters'] end - def test_added_filter_to_inheritance_graph - assert_equal [ :ensure_login ], TestController.before_filters + def test_added_action_to_inheritance_graph + assert_equal [ :ensure_login ], TestController.before_actions end def test_base_class_in_isolation - assert_equal [ ], ActionController::Base.before_filters + assert_equal [ ], ActionController::Base.before_actions end - def test_prepending_filter - assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_filters + def test_prepending_action + assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_actions end - def test_running_filters + def test_running_actions test_process(PrependingController) assert_equal %w( wonderful_life ensure_login ), assigns["ran_filter"] end - def test_running_filters_with_proc + def test_running_actions_with_proc test_process(ProcController) - assert assigns["ran_proc_filter"] + assert assigns["ran_proc_action"] end - def test_running_filters_with_implicit_proc + def test_running_actions_with_implicit_proc test_process(ImplicitProcController) - assert assigns["ran_proc_filter"] + assert assigns["ran_proc_action"] end - def test_running_filters_with_class + def test_running_actions_with_class test_process(AuditController) assert assigns["was_audited"] end - def test_running_anomolous_yet_valid_condition_filters + def test_running_anomolous_yet_valid_condition_actions test_process(AnomolousYetValidConditionController) assert_equal %w( ensure_login ), assigns["ran_filter"] - assert assigns["ran_class_filter"] - assert assigns["ran_proc_filter1"] - assert assigns["ran_proc_filter2"] + assert assigns["ran_class_action"] + assert assigns["ran_proc_action1"] + assert assigns["ran_proc_action2"] - test_process(AnomolousYetValidConditionController, "show_without_filter") + test_process(AnomolousYetValidConditionController, "show_without_action") assert_nil assigns["ran_filter"] - assert !assigns["ran_class_filter"] - assert !assigns["ran_proc_filter1"] - assert !assigns["ran_proc_filter2"] + assert !assigns["ran_class_action"] + assert !assigns["ran_proc_action1"] + assert !assigns["ran_proc_action2"] end def test_running_conditional_options @@ -614,59 +614,59 @@ class FilterTest < ActionController::TestCase assert_equal %w( ensure_login ), assigns["ran_filter"] end - def test_skipping_class_filters + def test_skipping_class_actions test_process(ClassController) - assert_equal true, assigns["ran_class_filter"] + assert_equal true, assigns["ran_class_action"] skipping_class_controller = Class.new(ClassController) do - skip_before_filter ConditionalClassFilter + skip_before_action ConditionalClassFilter end test_process(skipping_class_controller) - assert_nil assigns['ran_class_filter'] + assert_nil assigns['ran_class_action'] end - def test_running_collection_condition_filters + def test_running_collection_condition_actions test_process(ConditionalCollectionFilterController) assert_equal %w( ensure_login ), assigns["ran_filter"] - test_process(ConditionalCollectionFilterController, "show_without_filter") + test_process(ConditionalCollectionFilterController, "show_without_action") assert_nil assigns["ran_filter"] test_process(ConditionalCollectionFilterController, "another_action") assert_nil assigns["ran_filter"] end - def test_running_only_condition_filters + def test_running_only_condition_actions test_process(OnlyConditionSymController) assert_equal %w( ensure_login ), assigns["ran_filter"] - test_process(OnlyConditionSymController, "show_without_filter") + test_process(OnlyConditionSymController, "show_without_action") assert_nil assigns["ran_filter"] test_process(OnlyConditionProcController) - assert assigns["ran_proc_filter"] - test_process(OnlyConditionProcController, "show_without_filter") - assert !assigns["ran_proc_filter"] + assert assigns["ran_proc_action"] + test_process(OnlyConditionProcController, "show_without_action") + assert !assigns["ran_proc_action"] test_process(OnlyConditionClassController) - assert assigns["ran_class_filter"] - test_process(OnlyConditionClassController, "show_without_filter") - assert !assigns["ran_class_filter"] + assert assigns["ran_class_action"] + test_process(OnlyConditionClassController, "show_without_action") + assert !assigns["ran_class_action"] end - def test_running_except_condition_filters + def test_running_except_condition_actions test_process(ExceptConditionSymController) assert_equal %w( ensure_login ), assigns["ran_filter"] - test_process(ExceptConditionSymController, "show_without_filter") + test_process(ExceptConditionSymController, "show_without_action") assert_nil assigns["ran_filter"] test_process(ExceptConditionProcController) - assert assigns["ran_proc_filter"] - test_process(ExceptConditionProcController, "show_without_filter") - assert !assigns["ran_proc_filter"] + assert assigns["ran_proc_action"] + test_process(ExceptConditionProcController, "show_without_action") + assert !assigns["ran_proc_action"] test_process(ExceptConditionClassController) - assert assigns["ran_class_filter"] - test_process(ExceptConditionClassController, "show_without_filter") - assert !assigns["ran_class_filter"] + assert assigns["ran_class_action"] + test_process(ExceptConditionClassController, "show_without_action") + assert !assigns["ran_class_action"] end def test_running_only_condition_and_conditional_options @@ -674,70 +674,70 @@ class FilterTest < ActionController::TestCase assert_not assigns["ran_conditional_index_proc"] end - def test_running_before_and_after_condition_filters + def test_running_before_and_after_condition_actions test_process(BeforeAndAfterConditionController) assert_equal %w( ensure_login clean_up_tmp), assigns["ran_filter"] - test_process(BeforeAndAfterConditionController, "show_without_filter") + test_process(BeforeAndAfterConditionController, "show_without_action") assert_nil assigns["ran_filter"] end - def test_around_filter + def test_around_action test_process(AroundFilterController) assert assigns["before_ran"] assert assigns["after_ran"] end - def test_before_after_class_filter + def test_before_after_class_action test_process(BeforeAfterClassFilterController) assert assigns["before_ran"] assert assigns["after_ran"] end - def test_having_properties_in_around_filter + def test_having_properties_in_around_action test_process(AroundFilterController) assert_equal "before and after", assigns["execution_log"] end - def test_prepending_and_appending_around_filter + def test_prepending_and_appending_around_action test_process(MixedFilterController) assert_equal " before aroundfilter before procfilter before appended aroundfilter " + " after appended aroundfilter after procfilter after aroundfilter ", MixedFilterController.execution_log end - def test_rendering_breaks_filtering_chain + def test_rendering_breaks_actioning_chain response = test_process(RenderingController) assert_equal "something else", response.body assert !assigns["ran_action"] end - def test_before_filter_rendering_breaks_filtering_chain_for_after_filter + def test_before_action_rendering_breaks_actioning_chain_for_after_action test_process(RenderingController) - assert_equal %w( before_filter_rendering ), assigns["ran_filter"] + assert_equal %w( before_action_rendering ), assigns["ran_filter"] assert !assigns["ran_action"] end - def test_before_filter_redirects_breaks_filtering_chain_for_after_filter - test_process(BeforeFilterRedirectionController) + def test_before_action_redirects_breaks_actioning_chain_for_after_action + test_process(BeforeActionRedirectionController) assert_response :redirect - assert_equal "http://test.host/filter_test/before_filter_redirection/target_of_redirection", redirect_to_url - assert_equal %w( before_filter_redirects ), assigns["ran_filter"] + assert_equal "http://test.host/filter_test/before_action_redirection/target_of_redirection", redirect_to_url + assert_equal %w( before_action_redirects ), assigns["ran_filter"] end - def test_before_filter_rendering_breaks_filtering_chain_for_preprend_after_filter - test_process(RenderingForPrependAfterFilterController) - assert_equal %w( before_filter_rendering ), assigns["ran_filter"] + def test_before_action_rendering_breaks_actioning_chain_for_preprend_after_action + test_process(RenderingForPrependAfterActionController) + assert_equal %w( before_action_rendering ), assigns["ran_filter"] assert !assigns["ran_action"] end - def test_before_filter_redirects_breaks_filtering_chain_for_preprend_after_filter - test_process(BeforeFilterRedirectionForPrependAfterFilterController) + def test_before_action_redirects_breaks_actioning_chain_for_preprend_after_action + test_process(BeforeActionRedirectionForPrependAfterActionController) assert_response :redirect - assert_equal "http://test.host/filter_test/before_filter_redirection_for_prepend_after_filter/target_of_redirection", redirect_to_url - assert_equal %w( before_filter_redirects ), assigns["ran_filter"] + assert_equal "http://test.host/filter_test/before_action_redirection_for_prepend_after_action/target_of_redirection", redirect_to_url + assert_equal %w( before_action_redirects ), assigns["ran_filter"] end - def test_filters_with_mixed_specialization_run_in_order + def test_actions_with_mixed_specialization_run_in_order assert_nothing_raised do response = test_process(MixedSpecializationController, 'bar') assert_equal 'bar', response.body @@ -758,7 +758,7 @@ class FilterTest < ActionController::TestCase end end - def test_running_prepended_before_and_after_filter + def test_running_prepended_before_and_after_action test_process(PrependingBeforeAndAfterController) assert_equal %w( before_all between_before_all_and_after_all after_all ), assigns["ran_filter"] end @@ -775,26 +775,26 @@ class FilterTest < ActionController::TestCase assert_equal %w( find_record ensure_login ), assigns["ran_filter"] end - def test_conditional_skipping_of_filters + def test_conditional_skipping_of_actions test_process(ConditionalSkippingController, "login") assert_nil assigns["ran_filter"] test_process(ConditionalSkippingController, "change_password") assert_equal %w( ensure_login find_user ), assigns["ran_filter"] test_process(ConditionalSkippingController, "login") - assert !@controller.instance_variable_defined?("@ran_after_filter") + assert !@controller.instance_variable_defined?("@ran_after_action") test_process(ConditionalSkippingController, "change_password") - assert_equal %w( clean_up ), @controller.instance_variable_get("@ran_after_filter") + assert_equal %w( clean_up ), @controller.instance_variable_get("@ran_after_action") end - def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional + def test_conditional_skipping_of_actions_when_parent_action_is_also_conditional test_process(ChildOfConditionalParentController) assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter'] test_process(ChildOfConditionalParentController, 'another_action') assert_nil assigns['ran_filter'] end - def test_condition_skipping_of_filters_when_siblings_also_have_conditions + def test_condition_skipping_of_actions_when_siblings_also_have_conditions test_process(ChildOfConditionalParentController) assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter'] test_process(AnotherChildOfConditionalParentController) @@ -808,7 +808,7 @@ class FilterTest < ActionController::TestCase assert_nil assigns['ran_filter'] end - def test_a_rescuing_around_filter + def test_a_rescuing_around_action response = nil assert_nothing_raised do response = test_process(RescuedController) @@ -818,7 +818,7 @@ class FilterTest < ActionController::TestCase assert_equal("I rescued this: #<FilterTest::ErrorToRescue: Something made the bad noise.>", response.body) end - def test_filters_obey_only_and_except_for_implicit_actions + def test_actions_obey_only_and_except_for_implicit_actions test_process(ImplicitActionsController, 'show') assert_equal 'Except', assigns(:except) assert_nil assigns(:only) @@ -852,7 +852,7 @@ class PostsController < ActionController::Base include AroundExceptions end - module_eval %w(raises_before raises_after raises_both no_raise no_filter).map { |action| "def #{action}; default_action end" }.join("\n") + module_eval %w(raises_before raises_after raises_both no_raise no_action).map { |action| "def #{action}; default_action end" }.join("\n") private def default_action @@ -861,9 +861,9 @@ class PostsController < ActionController::Base end class ControllerWithSymbolAsFilter < PostsController - around_filter :raise_before, :only => :raises_before - around_filter :raise_after, :only => :raises_after - around_filter :without_exception, :only => :no_raise + around_action :raise_before, :only => :raises_before + around_action :raise_after, :only => :raises_after + around_action :without_exception, :only => :no_raise private def raise_before @@ -895,7 +895,7 @@ class ControllerWithFilterClass < PostsController end end - around_filter YieldingFilter, :only => :raises_after + around_action YieldingFilter, :only => :raises_after end class ControllerWithFilterInstance < PostsController @@ -906,11 +906,11 @@ class ControllerWithFilterInstance < PostsController end end - around_filter YieldingFilter.new, :only => :raises_after + around_action YieldingFilter.new, :only => :raises_after end class ControllerWithProcFilter < PostsController - around_filter(:only => :no_raise) do |c,b| + around_action(:only => :no_raise) do |c,b| c.instance_variable_set(:"@before", true) b.call c.instance_variable_set(:"@after", true) @@ -918,14 +918,14 @@ class ControllerWithProcFilter < PostsController end class ControllerWithNestedFilters < ControllerWithSymbolAsFilter - around_filter :raise_before, :raise_after, :without_exception, :only => :raises_both + around_action :raise_before, :raise_after, :without_exception, :only => :raises_both end class ControllerWithAllTypesOfFilters < PostsController - before_filter :before - around_filter :around - after_filter :after - around_filter :around_again + before_action :before + around_action :around + after_action :after + around_action :around_again private def before @@ -951,8 +951,8 @@ class ControllerWithAllTypesOfFilters < PostsController end class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters - skip_filter :around_again - skip_filter :after + skip_action_callback :around_again + skip_action_callback :after end class YieldingAroundFiltersTest < ActionController::TestCase @@ -963,7 +963,7 @@ class YieldingAroundFiltersTest < ActionController::TestCase assert_nothing_raised { test_process(controller,'no_raise') } assert_nothing_raised { test_process(controller,'raises_before') } assert_nothing_raised { test_process(controller,'raises_after') } - assert_nothing_raised { test_process(controller,'no_filter') } + assert_nothing_raised { test_process(controller,'no_action') } end def test_with_symbol @@ -992,7 +992,7 @@ class YieldingAroundFiltersTest < ActionController::TestCase assert assigns['after'] end - def test_nested_filters + def test_nested_actions controller = ControllerWithNestedFilters assert_nothing_raised do begin @@ -1008,31 +1008,31 @@ class YieldingAroundFiltersTest < ActionController::TestCase end end - def test_filter_order_with_all_filter_types + def test_action_order_with_all_action_types test_process(ControllerWithAllTypesOfFilters,'no_raise') assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) after around (after yield)', assigns['ran_filter'].join(' ') end - def test_filter_order_with_skip_filter_method + def test_action_order_with_skip_action_method test_process(ControllerWithTwoLessFilters,'no_raise') assert_equal 'before around (before yield) around (after yield)', assigns['ran_filter'].join(' ') end - def test_first_filter_in_multiple_before_filter_chain_halts + def test_first_action_in_multiple_before_action_chain_halts controller = ::FilterTest::TestMultipleFiltersController.new response = test_process(controller, 'fail_1') assert_equal ' ', response.body assert_equal 1, controller.instance_variable_get(:@try) end - def test_second_filter_in_multiple_before_filter_chain_halts + def test_second_action_in_multiple_before_action_chain_halts controller = ::FilterTest::TestMultipleFiltersController.new response = test_process(controller, 'fail_2') assert_equal ' ', response.body assert_equal 2, controller.instance_variable_get(:@try) end - def test_last_filter_in_multiple_before_filter_chain_halts + def test_last_action_in_multiple_before_action_chain_halts controller = ::FilterTest::TestMultipleFiltersController.new response = test_process(controller, 'fail_3') assert_equal ' ', response.body diff --git a/actionpack/test/controller/http_basic_authentication_test.rb b/actionpack/test/controller/http_basic_authentication_test.rb index 90548d4294..9052fc6962 100644 --- a/actionpack/test/controller/http_basic_authentication_test.rb +++ b/actionpack/test/controller/http_basic_authentication_test.rb @@ -129,6 +129,13 @@ class HttpBasicAuthenticationTest < ActionController::TestCase assert_response :unauthorized end + test "authentication request with wrong scheme" do + header = 'Bearer ' + encode_credentials('David', 'Goliath').split(' ', 2)[1] + @request.env['HTTP_AUTHORIZATION'] = header + get :search + assert_response :unauthorized + end + private def encode_credentials(username, password) diff --git a/actionpack/test/controller/http_token_authentication_test.rb b/actionpack/test/controller/http_token_authentication_test.rb index 86b94652ce..8c6c8a0aa7 100644 --- a/actionpack/test/controller/http_token_authentication_test.rb +++ b/actionpack/test/controller/http_token_authentication_test.rb @@ -132,13 +132,50 @@ class HttpTokenAuthenticationTest < ActionController::TestCase assert_equal(expected, actual) end - private + test "token_and_options returns empty string with empty token" do + token = '' + actual = ActionController::HttpAuthentication::Token.token_and_options(sample_request(token)).first + expected = token + assert_equal(expected, actual) + end - def sample_request(token) - @sample_request ||= OpenStruct.new authorization: %{Token token="#{token}"} + test "token_and_options returns correct token with nounce option" do + token = "rcHu+HzSFw89Ypyhn/896A=" + nonce_hash = {nonce: "123abc"} + actual = ActionController::HttpAuthentication::Token.token_and_options(sample_request(token, nonce_hash)) + expected_token = token + expected_nonce = {"nonce" => nonce_hash[:nonce]} + assert_equal(expected_token, actual.first) + assert_equal(expected_nonce, actual.last) end - def encode_credentials(token, options = {}) - ActionController::HttpAuthentication::Token.encode_credentials(token, options) + test "token_and_options returns nil with no value after the equal sign" do + actual = ActionController::HttpAuthentication::Token.token_and_options(malformed_request).first + expected = nil + assert_equal(expected, actual) + end + + test "raw_params returns a tuple of two key value pair strings" do + auth = sample_request("rcHu+HzSFw89Ypyhn/896A=").authorization.to_s + actual = ActionController::HttpAuthentication::Token.raw_params(auth) + expected = ["token=\"rcHu+HzSFw89Ypyhn/896A=\"", "nonce=\"def\""] + assert_equal(expected, actual) end + + private + + def sample_request(token, options = {nonce: "def"}) + authorization = options.inject([%{Token token="#{token}"}]) do |arr, (k, v)| + arr << "#{k}=\"#{v}\"" + end.join(", ") + @sample_request ||= OpenStruct.new authorization: authorization + end + + def malformed_request + @malformed_request ||= OpenStruct.new authorization: %{Token token=} + end + + def encode_credentials(token, options = {}) + ActionController::HttpAuthentication::Token.encode_credentials(token, options) + end end diff --git a/actionpack/test/controller/live_stream_test.rb b/actionpack/test/controller/live_stream_test.rb index 1dca36374a..0500b7c789 100644 --- a/actionpack/test/controller/live_stream_test.rb +++ b/actionpack/test/controller/live_stream_test.rb @@ -202,6 +202,39 @@ module ActionController response.stream.write '' response.stream.write params[:widget][:didnt_check_for_nil] end + + def overfill_buffer_and_die + # Write until the buffer is full. It doesn't expose that + # information directly, so we must hard-code its size: + 10.times do + response.stream.write '.' + end + # .. plus one more, because the #each frees up a slot: + response.stream.write '.' + + latch.release + + # This write will block, and eventually raise + response.stream.write 'x' + + 20.times do + response.stream.write '.' + end + end + + def ignore_client_disconnect + response.stream.ignore_disconnect = true + + response.stream.write '' # commit + + # These writes will be ignored + 15.times do + response.stream.write 'x' + end + + logger.info 'Work complete' + latch.release + end end tests TestController @@ -264,6 +297,62 @@ module ActionController assert t.join(3), 'timeout expired before the thread terminated' end + def test_abort_with_full_buffer + @controller.latch = ActiveSupport::Concurrency::Latch.new + + @request.parameters[:format] = 'plain' + @controller.request = @request + @controller.response = @response + + got_error = ActiveSupport::Concurrency::Latch.new + @response.stream.on_error do + ActionController::Base.logger.warn 'Error while streaming' + got_error.release + end + + t = Thread.new(@response) { |resp| + resp.await_commit + _, _, body = resp.to_a + body.each do |part| + @controller.latch.await + body.close + break + end + } + + capture_log_output do |output| + @controller.process :overfill_buffer_and_die + t.join + got_error.await + assert_match 'Error while streaming', output.rewind && output.read + end + end + + def test_ignore_client_disconnect + @controller.latch = ActiveSupport::Concurrency::Latch.new + + @controller.request = @request + @controller.response = @response + + t = Thread.new(@response) { |resp| + resp.await_commit + _, _, body = resp.to_a + body.each do |part| + body.close + break + end + } + + capture_log_output do |output| + @controller.process :ignore_client_disconnect + t.join + Timeout.timeout(3) do + @controller.latch.await + end + assert_match 'Work complete', output.rewind && output.read + end + end + def test_thread_locals_get_copied @controller.tc = self Thread.current[:originating_thread] = Thread.current.object_id diff --git a/actionpack/test/controller/localized_templates_test.rb b/actionpack/test/controller/localized_templates_test.rb index c95ef8a0c7..27871ef351 100644 --- a/actionpack/test/controller/localized_templates_test.rb +++ b/actionpack/test/controller/localized_templates_test.rb @@ -8,22 +8,24 @@ end class LocalizedTemplatesTest < ActionController::TestCase tests LocalizedController + setup do + @old_locale = I18n.locale + end + + teardown do + I18n.locale = @old_locale + end + def test_localized_template_is_used - old_locale = I18n.locale I18n.locale = :de get :hello_world assert_equal "Gutten Tag", @response.body - ensure - I18n.locale = old_locale end def test_default_locale_template_is_used_when_locale_is_missing - old_locale = I18n.locale I18n.locale = :dk get :hello_world assert_equal "Hello World", @response.body - ensure - I18n.locale = old_locale end def test_use_fallback_locales @@ -36,13 +38,9 @@ class LocalizedTemplatesTest < ActionController::TestCase end def test_localized_template_has_correct_header_with_no_format_in_template_name - old_locale = I18n.locale I18n.locale = :it - get :hello_world assert_equal "Ciao Mondo", @response.body assert_equal "text/html", @response.content_type - ensure - I18n.locale = old_locale end end diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb index 41503e11a8..c89b95de3b 100644 --- a/actionpack/test/controller/mime/respond_to_test.rb +++ b/actionpack/test/controller/mime/respond_to_test.rb @@ -128,6 +128,12 @@ class RespondToController < ActionController::Base end end + def json_with_callback + respond_to do |type| + type.json { render :json => 'JS', :callback => 'alert' } + end + end + def iphone_with_html_response_type request.format = :iphone if request.env["HTTP_ACCEPT"] == "text/iphone" @@ -511,6 +517,13 @@ class RespondToControllerTest < ActionController::TestCase assert_equal '<html><div id="html">HTML for all_types_with_layout</div></html>', @response.body end + def test_json_with_callback_sets_javascript_content_type + @request.accept = 'application/json' + get :json_with_callback + assert_equal 'alert(JS)', @response.body + assert_equal 'text/javascript', @response.content_type + end + def test_xhr xhr :get, :js_or_html assert_equal 'JS', @response.body diff --git a/actionpack/test/controller/mime/respond_with_test.rb b/actionpack/test/controller/mime/respond_with_test.rb index 416b3b81a5..115f3b2f41 100644 --- a/actionpack/test/controller/mime/respond_with_test.rb +++ b/actionpack/test/controller/mime/respond_with_test.rb @@ -2,6 +2,10 @@ require 'abstract_unit' require 'controller/fake_models' class RespondWithController < ActionController::Base + class CustomerWithJson < Customer + def to_json; super; end + end + respond_to :html, :json, :touch respond_to :xml, :except => :using_resource_with_block respond_to :js, :only => [ :using_resource_with_block, :using_resource, 'using_hash_resource' ] @@ -38,6 +42,10 @@ class RespondWithController < ActionController::Base respond_with(resource, :location => "http://test.host/", :status => :created) end + def using_resource_with_json + respond_with(CustomerWithJson.new("david", request.delete? ? nil : 13)) + end + def using_invalid_resource_with_template respond_with(resource) end @@ -380,9 +388,8 @@ class RespondWithControllerTest < ActionController::TestCase end def test_using_resource_for_put_with_json_yields_no_content_on_success - Customer.any_instance.stubs(:to_json).returns('{"name": "David"}') @request.accept = "application/json" - put :using_resource + put :using_resource_with_json assert_equal "application/json", @response.content_type assert_equal 204, @response.status assert_equal "", @response.body @@ -431,10 +438,9 @@ class RespondWithControllerTest < ActionController::TestCase end def test_using_resource_for_delete_with_json_yields_no_content_on_success - Customer.any_instance.stubs(:to_json).returns('{"name": "David"}') Customer.any_instance.stubs(:destroyed?).returns(true) @request.accept = "application/json" - delete :using_resource + delete :using_resource_with_json assert_equal "application/json", @response.content_type assert_equal 204, @response.status assert_equal "", @response.body @@ -643,6 +649,8 @@ class RespondWithControllerTest < ActionController::TestCase get :index, format: 'csv' assert_equal Mime::CSV, @response.content_type assert_equal "c,s,v", @response.body + ensure + ActionController::Renderers.remove :csv end def test_raises_missing_renderer_if_an_api_behavior_with_no_renderer @@ -652,6 +660,23 @@ class RespondWithControllerTest < ActionController::TestCase end end + def test_removing_renderers + ActionController::Renderers.add :csv do |obj, options| + send_data obj.to_csv, type: Mime::CSV + end + @controller = CsvRespondWithController.new + @request.accept = "text/csv" + get :index, format: 'csv' + assert_equal Mime::CSV, @response.content_type + + ActionController::Renderers.remove :csv + assert_raise ActionController::MissingRenderer do + get :index, format: 'csv' + end + ensure + ActionController::Renderers.remove :csv + end + def test_error_is_raised_if_no_respond_to_is_declared_and_respond_with_is_called @controller = EmptyRespondWithController.new @request.accept = "*/*" diff --git a/actionpack/test/controller/new_base/bare_metal_test.rb b/actionpack/test/controller/new_base/bare_metal_test.rb index 7396c850ad..246ba099af 100644 --- a/actionpack/test/controller/new_base/bare_metal_test.rb +++ b/actionpack/test/controller/new_base/bare_metal_test.rb @@ -2,6 +2,8 @@ require "abstract_unit" module BareMetalTest class BareController < ActionController::Metal + include ActionController::RackDelegation + def index self.response_body = "Hello world" end @@ -81,8 +83,8 @@ module BareMetalTest assert_nil headers['Content-Length'] end - test "head :continue (101) does not return a content-type header" do - headers = HeadController.action(:continue).call(Rack::MockRequest.env_for("/")).second + test "head :switching_protocols (101) does not return a content-type header" do + headers = HeadController.action(:switching_protocols).call(Rack::MockRequest.env_for("/")).second assert_nil headers['Content-Type'] assert_nil headers['Content-Length'] end diff --git a/actionpack/test/controller/parameters/always_permitted_parameters_test.rb b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb new file mode 100644 index 0000000000..059f310d49 --- /dev/null +++ b/actionpack/test/controller/parameters/always_permitted_parameters_test.rb @@ -0,0 +1,29 @@ +require 'abstract_unit' +require 'action_controller/metal/strong_parameters' + +class AlwaysPermittedParametersTest < ActiveSupport::TestCase + def setup + ActionController::Parameters.action_on_unpermitted_parameters = :raise + ActionController::Parameters.always_permitted_parameters = %w( controller action format ) + end + + def teardown + ActionController::Parameters.action_on_unpermitted_parameters = false + ActionController::Parameters.always_permitted_parameters = %w( controller action ) + end + + test "shows deprecations warning on NEVER_UNPERMITTED_PARAMS" do + assert_deprecated do + ActionController::Parameters::NEVER_UNPERMITTED_PARAMS + end + end + + test "permits parameters that are whitelisted" do + params = ActionController::Parameters.new({ + book: { pages: 65 }, + format: "json" + }) + permitted = params.permit book: [:pages] + assert permitted.permitted? + end +end diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb index 33a91d72d9..aa894ffa17 100644 --- a/actionpack/test/controller/parameters/parameters_permit_test.rb +++ b/actionpack/test/controller/parameters/parameters_permit_test.rb @@ -167,9 +167,26 @@ class ParametersPermitTest < ActiveSupport::TestCase end end + # Strong params has an optimization to avoid looping every time you read + # a key whose value is an array and building a new object. We check that + # optimization here. test 'arrays are converted at most once' do params = ActionController::Parameters.new(foo: [{}]) - assert params[:foo].equal?(params[:foo]) + assert_same params[:foo], params[:foo] + end + + # Strong params has an internal cache to avoid duplicated loops in the most + # common usage pattern. See the docs of the method `converted_arrays`. + # + # This test checks that if we push a hash to an array (in-place modification) + # the cache does not get fooled, the hash is still wrapped as strong params, + # and not permitted. + test 'mutated arrays are detected' do + params = ActionController::Parameters.new(users: [{id: 1}]) + + permitted = params.permit(users: [:id]) + permitted[:users] << {injected: 1} + assert_not permitted[:users].last.permitted? end test "fetch doesnt raise ParameterMissing exception if there is a default" do diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index 11ccb6cf3b..645ecae220 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -337,14 +337,26 @@ class IrregularInflectionParamsWrapperTest < ActionController::TestCase tests ParamswrappernewsController def test_uses_model_attribute_names_with_irregular_inflection - ActiveSupport::Inflector.inflections do |inflect| - inflect.irregular 'paramswrappernews_item', 'paramswrappernews' - end + with_dup do + ActiveSupport::Inflector.inflections do |inflect| + inflect.irregular 'paramswrappernews_item', 'paramswrappernews' + end - with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, { 'username' => 'sikachu', 'test_attr' => 'test_value' } - assert_parameters({ 'username' => 'sikachu', 'test_attr' => 'test_value', 'paramswrappernews_item' => { 'test_attr' => 'test_value' }}) + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :parse, { 'username' => 'sikachu', 'test_attr' => 'test_value' } + assert_parameters({ 'username' => 'sikachu', 'test_attr' => 'test_value', 'paramswrappernews_item' => { 'test_attr' => 'test_value' }}) + end end end + + private + + def with_dup + original = ActiveSupport::Inflector::Inflections.instance_variable_get(:@__instance__)[:en] + ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original.dup) + yield + ensure + ActiveSupport::Inflector::Inflections.instance_variable_set(:@__instance__, en: original) + end end diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb index b5e74e373d..af50e11261 100644 --- a/actionpack/test/controller/render_other_test.rb +++ b/actionpack/test/controller/render_other_test.rb @@ -1,9 +1,5 @@ require 'abstract_unit' -ActionController.add_renderer :simon do |says, options| - self.content_type = Mime::TEXT - self.response_body = "Simon says: #{says}" -end class RenderOtherTest < ActionController::TestCase class TestController < ActionController::Base @@ -15,7 +11,14 @@ class RenderOtherTest < ActionController::TestCase tests TestController def test_using_custom_render_option + ActionController.add_renderer :simon do |says, options| + self.content_type = Mime::TEXT + self.response_body = "Simon says: #{says}" + end + get :render_simon_says assert_equal "Simon says: foo", @response.body + ensure + ActionController.remove_renderer :simon end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 26806fb03f..9926130c02 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -242,6 +242,8 @@ class MetalTestController < ActionController::Metal include AbstractController::Rendering include ActionView::Rendering include ActionController::Rendering + include ActionController::RackDelegation + def accessing_logger_in_template render :inline => "<%= logger.class %>" @@ -387,10 +389,6 @@ end class EtagRenderTest < ActionController::TestCase tests TestControllerWithExtraEtags - def setup - super - end - def test_multiple_etags @request.if_none_match = etag(["123", 'ab', :cde, [:f]]) get :fresh diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index 07c2115832..2a5aad9c0e 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -127,11 +127,12 @@ module RequestForgeryProtectionTests @token = "cf50faa3fe97702ca1ae" SecureRandom.stubs(:base64).returns(@token) + @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token ActionController::Base.request_forgery_protection_token = :custom_authenticity_token end def teardown - ActionController::Base.request_forgery_protection_token = nil + ActionController::Base.request_forgery_protection_token = @old_request_forgery_protection_token end def test_should_render_form_with_token_tag @@ -376,11 +377,12 @@ class RequestForgeryProtectionControllerUsingResetSessionTest < ActionController include RequestForgeryProtectionTests setup do + @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token ActionController::Base.request_forgery_protection_token = :custom_authenticity_token end teardown do - ActionController::Base.request_forgery_protection_token = nil + ActionController::Base.request_forgery_protection_token = @old_request_forgery_protection_token end test 'should emit a csrf-param meta tag and a csrf-token meta tag' do @@ -465,11 +467,12 @@ class CustomAuthenticityParamControllerTest < ActionController::TestCase @old_logger = ActionController::Base.logger @logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new @token = "foobar" + @old_request_forgery_protection_token = ActionController::Base.request_forgery_protection_token ActionController::Base.request_forgery_protection_token = @token end def teardown - ActionController::Base.request_forgery_protection_token = nil + ActionController::Base.request_forgery_protection_token = @old_request_forgery_protection_token super end diff --git a/actionpack/test/controller/required_params_test.rb b/actionpack/test/controller/required_params_test.rb index 25d0337212..6803dbbb62 100644 --- a/actionpack/test/controller/required_params_test.rb +++ b/actionpack/test/controller/required_params_test.rb @@ -24,10 +24,26 @@ class ActionControllerRequiredParamsTest < ActionController::TestCase post :create, { book: { name: "Mjallo!" } } assert_response :ok end + + test "required parameters with false value will not raise" do + post :create, { book: { name: false } } + assert_response :ok + end end class ParametersRequireTest < ActiveSupport::TestCase - test "required parameters must be present not merely not nil" do + + test "required parameters should accept and return false value" do + assert_equal(false, ActionController::Parameters.new(person: false).require(:person)) + end + + test "required parameters must not be nil" do + assert_raises(ActionController::ParameterMissing) do + ActionController::Parameters.new(person: nil).require(:person) + end + end + + test "required parameters must not be empty" do assert_raises(ActionController::ParameterMissing) do ActionController::Parameters.new(person: {}).require(:person) end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index b22bc2dc25..721dad4dd9 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -87,7 +87,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_symbols_with_dashes rs.draw do get '/:artist/:song-omg', :to => lambda { |env| - resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end @@ -99,7 +99,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_id_with_dash rs.draw do get '/journey/:id', :to => lambda { |env| - resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end @@ -111,7 +111,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_dash_with_custom_regexp rs.draw do get '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env| - resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end @@ -124,7 +124,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_pre_dash rs.draw do get '/:artist/omg-:song', :to => lambda { |env| - resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end @@ -136,7 +136,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase def test_pre_dash_with_custom_regexp rs.draw do get '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env| - resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] + resp = ActiveSupport::JSON.encode ActionDispatch::Request.new(env).path_parameters [200, {}, [resp]] } end @@ -243,6 +243,32 @@ class LegacyRouteSetTests < ActiveSupport::TestCase assert_equal 'clients', get(URI('http://clients.example.org/')) end + def test_scoped_lambda + scope_called = false + rs.draw do + scope '/foo', :constraints => lambda { |req| scope_called = true } do + get '/', :to => lambda { |env| [200, {}, %w{default}] } + end + end + + assert_equal 'default', get(URI('http://www.example.org/foo/')) + assert scope_called, "scope constraint should be called" + end + + def test_scoped_lambda_with_get_lambda + inner_called = false + + rs.draw do + scope '/foo', :constraints => lambda { |req| flunk "should not be called" } do + get '/', :constraints => lambda { |req| inner_called = true }, + :to => lambda { |env| [200, {}, %w{default}] } + end + end + + assert_equal 'default', get(URI('http://www.example.org/foo/')) + assert inner_called, "inner constraint should be called" + end + def test_empty_string_match rs.draw do get '/:username', :constraints => { :username => /[^\/]+/ }, diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb index aee139b95e..c002cf4d8f 100644 --- a/actionpack/test/controller/send_file_test.rb +++ b/actionpack/test/controller/send_file_test.rb @@ -9,6 +9,7 @@ end class SendFileController < ActionController::Base include TestFileUtils + include ActionController::Testing layout "layouts/standard" # to make sure layouts don't interfere attr_writer :options @@ -32,8 +33,6 @@ end class SendFileTest < ActionController::TestCase include TestFileUtils - Mime::Type.register "image/png", :png unless defined? Mime::PNG - def setup @controller = SendFileController.new @request = ActionController::TestRequest.new diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index fbc10baf21..3b3b15c061 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -164,7 +164,7 @@ XML end class DefaultUrlOptionsCachingController < ActionController::Base - before_filter { @dynamic_opt = 'opt' } + before_action { @dynamic_opt = 'opt' } def test_url_options_reset render text: url_for(params) @@ -662,7 +662,7 @@ XML def test_id_converted_to_string get :test_params, :id => 20, :foo => Object.new - assert_kind_of String, @request.path_parameters['id'] + assert_kind_of String, @request.path_parameters[:id] end def test_array_path_parameter_handled_properly @@ -673,17 +673,17 @@ XML end get :test_params, :path => ['hello', 'world'] - assert_equal ['hello', 'world'], @request.path_parameters['path'] - assert_equal 'hello/world', @request.path_parameters['path'].to_param + assert_equal ['hello', 'world'], @request.path_parameters[:path] + assert_equal 'hello/world', @request.path_parameters[:path].to_param end end def test_assert_realistic_path_parameters get :test_params, :id => 20, :foo => Object.new - # All elements of path_parameters should use string keys + # All elements of path_parameters should use Symbol keys @request.path_parameters.keys.each do |key| - assert_kind_of String, key + assert_kind_of Symbol, key end end @@ -737,12 +737,12 @@ XML assert_equal "baz", @request.filtered_parameters[:foo] end - def test_symbolized_path_params_reset_after_request + def test_path_params_reset_after_request get :test_params, :id => "foo" - assert_equal "foo", @request.symbolized_path_parameters[:id] + assert_equal "foo", @request.path_parameters[:id] @request.recycle! get :test_params - assert_nil @request.symbolized_path_parameters[:id] + assert_nil @request.path_parameters[:id] end def test_request_protocol_is_reset_after_request diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index 0c6df16325..7210c68e73 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -11,6 +11,26 @@ module AbstractController W.default_url_options.clear end + def test_nested_optional + klass = Class.new { + include ActionDispatch::Routing::RouteSet.new.tap { |r| + r.draw { + get "/foo/(:bar/(:baz))/:zot", :as => 'fun', + :controller => :articles, + :action => :index + } + }.url_helpers + self.default_url_options[:host] = 'example.com' + } + + path = klass.new.fun_path({:controller => :articles, + :baz => "baz", + :zot => "zot", + :only_path => true }) + # :bar key isn't provided + assert_equal '/foo/zot', path + end + def add_host! W.default_url_options[:host] = 'www.basecamphq.com' end @@ -75,7 +95,7 @@ module AbstractController end def test_subdomain_may_be_object - model = mock(:to_param => 'api') + model = Class.new { def self.to_param; 'api'; end } add_host! assert_equal('http://api.basecamphq.com/c/a/i', W.new.url_for(:subdomain => model, :controller => 'c', :action => 'a', :id => 'i') diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb index 58457b0c28..d8d3209dac 100644 --- a/actionpack/test/dispatch/mapper_test.rb +++ b/actionpack/test/dispatch/mapper_test.rb @@ -38,7 +38,7 @@ module ActionDispatch def test_mapping_requirements options = { :controller => 'foo', :action => 'bar', :via => :get } - m = Mapper::Mapping.new FakeSet.new, {}, '/store/:name(*rest)', options + m = Mapper::Mapping.build({}, '/store/:name(*rest)', options) _, _, requirements, _ = m.to_route assert_equal(/.+?/, requirements[:rest]) end @@ -72,7 +72,7 @@ module ActionDispatch mapper = Mapper.new fakeset mapper.get '/*path/foo/:bar', :to => 'pages#show' assert_equal '/*path/foo/:bar(.:format)', fakeset.conditions.first[:path_info] - assert_nil fakeset.requirements.first[:path] + assert_equal(/.+?/, fakeset.requirements.first[:path]) end def test_map_wildcard_with_multiple_wildcard @@ -80,7 +80,7 @@ module ActionDispatch mapper = Mapper.new fakeset mapper.get '/*foo/*bar', :to => 'pages#show' assert_equal '/*foo/*bar(.:format)', fakeset.conditions.first[:path_info] - assert_nil fakeset.requirements.first[:foo] + assert_equal(/.+?/, fakeset.requirements.first[:foo]) assert_equal(/.+?/, fakeset.requirements.first[:bar]) end diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 981cf2426e..d29cc8473e 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -1,8 +1,6 @@ require 'abstract_unit' class MimeTypeTest < ActiveSupport::TestCase - Mime::Type.register "image/png", :png unless defined? Mime::PNG - Mime::Type.register "application/pdf", :pdf unless defined? Mime::PDF test "parse single" do Mime::LOOKUP.keys.each do |mime_type| diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb index cdf00d84fb..ff4b644c16 100644 --- a/actionpack/test/dispatch/mount_test.rb +++ b/actionpack/test/dispatch/mount_test.rb @@ -31,10 +31,13 @@ class TestRoutingMount < ActionDispatch::IntegrationTest resources :users do mount FakeEngine, :at => "/fakeengine", :as => :fake_mounted_at_resource end + + mount SprocketsApp, :at => "/", :via => :get end + APP = RoutedRackApp.new Router def app - Router + APP end def test_app_name_is_properly_generated_when_engine_is_mounted_in_resources @@ -44,6 +47,11 @@ class TestRoutingMount < ActionDispatch::IntegrationTest "A named route should be defined with a parent's prefix" end + def test_mounting_at_root_path + get "/omg" + assert_equal " -- /omg", response.body + end + def test_mounting_sets_script_name get "/sprockets/omg" assert_equal "/sprockets -- /omg", response.body diff --git a/actionpack/test/dispatch/reloader_test.rb b/actionpack/test/dispatch/reloader_test.rb index ce9ccfcee8..62e8197e20 100644 --- a/actionpack/test/dispatch/reloader_test.rb +++ b/actionpack/test/dispatch/reloader_test.rb @@ -3,6 +3,11 @@ require 'abstract_unit' class ReloaderTest < ActiveSupport::TestCase Reloader = ActionDispatch::Reloader + teardown do + Reloader.reset_callbacks :prepare + Reloader.reset_callbacks :cleanup + end + def test_prepare_callbacks a = b = c = nil Reloader.to_prepare { |*args| a = b = c = 1 } diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb index 46c3e3d19d..926472163e 100644 --- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -149,7 +149,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest test "does not raise EOFError on GET request with multipart content-type" do with_routing do |set| set.draw do - get ':action', to: 'multipart_params_parsing_test/test' + get ':action', controller: 'multipart_params_parsing_test/test' end headers = { "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x" } get "/parse", {}, headers @@ -178,7 +178,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest def with_test_routing with_routing do |set| set.draw do - post ':action', :to => 'multipart_params_parsing_test/test' + post ':action', :controller => 'multipart_params_parsing_test/test' end yield end diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb index d82493140f..4e99c26e03 100644 --- a/actionpack/test/dispatch/request/query_string_parsing_test.rb +++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb @@ -105,6 +105,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest end test "perform_deep_munge" do + old_perform_deep_munge = ActionDispatch::Request::Utils.perform_deep_munge ActionDispatch::Request::Utils.perform_deep_munge = false begin assert_parses({"action" => nil}, "action") @@ -115,7 +116,7 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest assert_parses({"action" => {"foo" => [{"bar" => nil}]}}, "action[foo][][bar]") assert_parses({"action" => ['1',nil]}, "action[]=1&action[]") ensure - ActionDispatch::Request::Utils.perform_deep_munge = true + ActionDispatch::Request::Utils.perform_deep_munge = old_perform_deep_munge end end diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb index 9a77454f30..1de05cbf09 100644 --- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -130,10 +130,7 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest end test "ambiguous params returns a bad request" do - with_routing do |set| - set.draw do - post ':action', to: ::UrlEncodedParamsParsingTest::TestController - end + with_test_routing do post "/parse", "foo[]=bar&foo[4]=bar" assert_response :bad_request end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 0e7e34fa8b..1ef2b062dd 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -811,6 +811,7 @@ class RequestFormat < BaseRequestTest end test "ignore_accept_header" do + old_ignore_accept_header = ActionDispatch::Request.ignore_accept_header ActionDispatch::Request.ignore_accept_header = true begin @@ -840,7 +841,7 @@ class RequestFormat < BaseRequestTest request.expects(:parameters).at_least_once.returns({:format => :json}) assert_equal [ Mime::JSON ], request.formats ensure - ActionDispatch::Request.ignore_accept_header = false + ActionDispatch::Request.ignore_accept_header = old_ignore_accept_header end end end @@ -1071,7 +1072,7 @@ class RequestEtag < BaseRequestTest end end -class RequestVarient < BaseRequestTest +class RequestVariant < BaseRequestTest test "setting variant" do request = stub_request diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb index 959a3bc5cd..187b9a2420 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -178,6 +178,7 @@ class ResponseTest < ActiveSupport::TestCase end test "read x_frame_options, x_content_type_options and x_xss_protection" do + original_default_headers = ActionDispatch::Response.default_headers begin ActionDispatch::Response.default_headers = { 'X-Frame-Options' => 'DENY', @@ -193,11 +194,12 @@ class ResponseTest < ActiveSupport::TestCase assert_equal('nosniff', resp.headers['X-Content-Type-Options']) assert_equal('1;', resp.headers['X-XSS-Protection']) ensure - ActionDispatch::Response.default_headers = nil + ActionDispatch::Response.default_headers = original_default_headers end end test "read custom default_header" do + original_default_headers = ActionDispatch::Response.default_headers begin ActionDispatch::Response.default_headers = { 'X-XX-XXXX' => 'Here is my phone number' @@ -209,7 +211,7 @@ class ResponseTest < ActiveSupport::TestCase assert_equal('Here is my phone number', resp.headers['X-XX-XXXX']) ensure - ActionDispatch::Response.default_headers = nil + ActionDispatch::Response.default_headers = original_default_headers end end diff --git a/actionpack/test/dispatch/routing/concerns_test.rb b/actionpack/test/dispatch/routing/concerns_test.rb index 9f37701656..7ef513b0c8 100644 --- a/actionpack/test/dispatch/routing/concerns_test.rb +++ b/actionpack/test/dispatch/routing/concerns_test.rb @@ -36,7 +36,8 @@ class RoutingConcernsTest < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = RoutedRackApp.new Routes + def app; APP end def test_accessing_concern_from_resources get "/posts/1/comments" diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index cae6b312b6..269c7b4159 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -99,6 +99,16 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_namespace_without_controller_segment + draw do + namespace :admin do + get 'hello/:controllers/:action' + end + end + get '/admin/hello/foo/new' + assert_equal 'foo', @request.params["controllers"] + end + def test_session_singleton_resource draw do resource :session do @@ -351,8 +361,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest draw do controller(:global) do get 'global/hide_notice' - get 'global/export', :to => :export, :as => :export_request - get '/export/:id/:file', :to => :export, :as => :export_download, :constraints => { :file => /.*/ } + get 'global/export', :action => :export, :as => :export_request + get '/export/:id/:file', :action => :export, :as => :export_download, :constraints => { :file => /.*/ } get 'global/:action' end end @@ -720,8 +730,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest draw do resources :replies do member do - put :answer, :to => :mark_as_answer - delete :answer, :to => :unmark_as_answer + put :answer, :action => :mark_as_answer + delete :answer, :action => :unmark_as_answer end end end @@ -1178,7 +1188,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest controller :articles do scope '/articles', :as => 'article' do scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do - get '/:id', :to => :with_id, :as => "" + get '/:id', :action => :with_id, :as => "" end end end @@ -1425,7 +1435,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_scoped_controller_with_namespace_and_action draw do namespace :account do - get ':action/callback', :action => /twitter|github/, :to => "callbacks", :as => :callback + get ':action/callback', :action => /twitter|github/, :controller => "callbacks", :as => :callback end end @@ -1482,7 +1492,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_normalize_namespaced_matches draw do namespace :account do - get 'description', :to => :description, :as => "description" + get 'description', :action => :description, :as => "description" end end @@ -1723,7 +1733,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "whatever/:controller(/:action(/:id))" end - get 'whatever/foo/bar' + get '/whatever/foo/bar' assert_equal 'foo#bar', @response.body assert_equal 'http://www.example.com/whatever/foo/bar/1', @@ -1735,10 +1745,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "whatever/:controller(/:action(/:id))", :id => /\d+/ end - get 'whatever/foo/bar/show' + get '/whatever/foo/bar/show' assert_equal 'foo/bar#show', @response.body - get 'whatever/foo/bar/show/1' + get '/whatever/foo/bar/show/1' assert_equal 'foo/bar#show', @response.body assert_equal 'http://www.example.com/whatever/foo/bar/show', @@ -2012,6 +2022,28 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal '/blogs/1/posts/2/comments/new', new_blog_post_comment_path(:blog_id => 1, :post_id => 2) end + def test_direct_children_of_shallow_resources + draw do + resources :blogs do + resources :posts, shallow: true do + resources :comments + end + end + end + + post '/posts/1/comments' + assert_equal 'comments#create', @response.body + assert_equal '/posts/1/comments', post_comments_path('1') + + get '/posts/2/comments/new' + assert_equal 'comments#new', @response.body + assert_equal '/posts/2/comments/new', new_post_comment_path('2') + + get '/posts/1/comments' + assert_equal 'comments#index', @response.body + assert_equal '/posts/1/comments', post_comments_path('1') + end + def test_shallow_nested_resources_within_scope draw do scope '/hello' do @@ -2144,7 +2176,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end resources :invoices do get "outstanding" => "invoices#outstanding", :on => :collection - get "overdue", :to => :overdue, :on => :collection + get "overdue", :action => :overdue, :on => :collection get "print" => "invoices#print", :as => :print, :on => :member post "preview" => "invoices#preview", :as => :preview, :on => :new end @@ -2232,6 +2264,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal '/api/1.0/users/first.last.xml', api_user_path(:version => '1.0', :id => 'first.last', :format => :xml) end + def test_match_without_via + assert_raises(ArgumentError) do + draw do + match '/foo/bar', :to => 'files#show' + end + end + end + + def test_match_with_empty_via + assert_raises(ArgumentError) do + draw do + match '/foo/bar', :to => 'files#show', :via => [] + end + end + end + def test_glob_parameter_accepts_regexp draw do get '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ @@ -2287,12 +2335,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get "(/user/:username)/photos" => "photos#index" end - get 'user/bob/photos' + get '/user/bob/photos' assert_equal 'photos#index', @response.body assert_equal 'http://www.example.com/user/bob/photos', url_for(:controller => "photos", :action => "index", :username => "bob") - get 'photos' + get '/photos' assert_equal 'photos#index', @response.body assert_equal 'http://www.example.com/photos', url_for(:controller => "photos", :action => "index", :username => nil) @@ -2805,7 +2853,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - def test_symbolized_path_parameters_is_not_stale + def test_path_parameters_is_not_stale draw do scope '/countries/:country', :constraints => lambda { |params, req| %w(all France).include?(params[:country]) } do get '/', :to => 'countries#index' @@ -2970,7 +3018,9 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end assert_raise(ArgumentError) do - draw { controller("/feeds") { get '/feeds/:service', :to => :show } } + assert_deprecated do + draw { controller("/feeds") { get '/feeds/:service', :to => :show } } + end end assert_raise(ArgumentError) do @@ -3120,7 +3170,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get '/downloads/1/1.tar' assert_equal 'downloads#show', @response.body - assert_equal expected_params, @request.symbolized_path_parameters + assert_equal expected_params, @request.path_parameters assert_equal '/downloads/1/1.tar', download_path('1') assert_equal '/downloads/1/1.tar', download_path('1', '1') end @@ -3137,6 +3187,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal '/foo', foo_root_path end + def test_namespace_as_controller + draw do + namespace :foo do + get '/', to: '/bar#index', as: 'root' + end + end + + get '/foo' + assert_equal 'bar#index', @response.body + assert_equal '/foo', foo_root_path + end + def test_trailing_slash draw do resources :streams @@ -3217,6 +3279,58 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal '/admin/posts/1/comments', admin_post_comments_path('1') end + def test_mix_string_to_controller_action + draw do + get '/projects', controller: 'project_files', + action: 'index', + to: 'comments#index' + end + get '/projects' + assert_equal 'comments#index', @response.body + end + + def test_mix_string_to_controller + draw do + get '/projects', controller: 'project_files', + to: 'comments#index' + end + get '/projects' + assert_equal 'comments#index', @response.body + end + + def test_mix_string_to_action + draw do + get '/projects', action: 'index', + to: 'comments#index' + end + get '/projects' + assert_equal 'comments#index', @response.body + end + + def test_mix_symbol_to_controller_action + assert_deprecated do + draw do + get '/projects', controller: 'project_files', + action: 'index', + to: :show + end + end + get '/projects' + assert_equal 'project_files#show', @response.body + end + + def test_mix_string_to_controller_action_no_hash + assert_deprecated do + draw do + get '/projects', controller: 'project_files', + action: 'index', + to: 'show' + end + end + get '/projects' + assert_equal 'show#index', @response.body + end + def test_shallow_path_and_prefix_are_not_added_to_non_shallow_routes draw do scope shallow_path: 'projects', shallow_prefix: 'project' do @@ -3329,19 +3443,19 @@ private def draw(&block) self.class.stub_controllers do |routes| - @app = routes - @app.default_url_options = { host: 'www.example.com' } - @app.draw(&block) + routes.default_url_options = { host: 'www.example.com' } + routes.draw(&block) + @app = RoutedRackApp.new routes end end def url_for(options = {}) - @app.url_helpers.url_for(options) + @app.routes.url_helpers.url_for(options) end def method_missing(method, *args, &block) if method.to_s =~ /_(path|url)$/ - @app.url_helpers.send(method, *args, &block) + @app.routes.url_helpers.send(method, *args, &block) else super end @@ -3368,12 +3482,14 @@ end class TestAltApp < ActionDispatch::IntegrationTest class AltRequest + attr_accessor :path_parameters, :path_info, :script_name + attr_reader :env + def initialize(env) + @path_parameters = {} @env = env - end - - def path_info - "/" + @path_info = "/" + @script_name = "" end def request_method @@ -3407,8 +3523,10 @@ class TestAltApp < ActionDispatch::IntegrationTest get "/" => TestAltApp::AltApp.new end + APP = build_app AltRoutes + def app - AltRoutes + APP end def test_alt_request_without_header @@ -3435,15 +3553,16 @@ class TestAppendingRoutes < ActionDispatch::IntegrationTest def setup super s = self - @app = ActionDispatch::Routing::RouteSet.new - @app.append do + routes = ActionDispatch::Routing::RouteSet.new + routes.append do get '/hello' => s.simple_app('fail') get '/goodbye' => s.simple_app('goodbye') end - @app.draw do + routes.draw do get '/hello' => s.simple_app('hello') end + @app = self.class.build_app routes end def test_goodbye_should_be_available @@ -3472,8 +3591,38 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest end def draw(&block) - @app = ActionDispatch::Routing::RouteSet.new - @app.draw(&block) + routes = ActionDispatch::Routing::RouteSet.new + routes.draw(&block) + @app = self.class.build_app routes + end + + def test_missing_controller + ex = assert_raises(ArgumentError) { + draw do + get '/foo/bar', :action => :index + end + } + assert_match(/Missing :controller/, ex.message) + end + + def test_missing_action + ex = assert_raises(ArgumentError) { + assert_deprecated do + draw do + get '/foo/bar', :to => 'foo' + end + end + } + assert_match(/Missing :action/, ex.message) + end + + def test_missing_action_on_hash + ex = assert_raises(ArgumentError) { + draw do + get '/foo/bar', :to => 'foo#' + end + } + assert_match(/Missing :action/, ex.message) end def test_valid_controller_options_inside_namespace @@ -3492,7 +3641,7 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest resources :storage_files, :controller => 'admin/storage_files' end - get 'storage_files' + get '/storage_files' assert_equal "admin/storage_files#index", @response.body end @@ -3517,6 +3666,16 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest assert_match "'Admin::StorageFiles' is not a supported controller name", e.message end + + def test_warn_with_ruby_constant_syntax_no_colons + e = assert_raise(ArgumentError) do + draw do + resources :storage_files, :controller => 'Admin' + end + end + + assert_match "'Admin' is not a supported controller name", e.message + end end class TestDefaultScope < ActionDispatch::IntegrationTest @@ -3534,8 +3693,10 @@ class TestDefaultScope < ActionDispatch::IntegrationTest resources :posts end + APP = build_app DefaultScopeRoutes + def app - DefaultScopeRoutes + APP end include DefaultScopeRoutes.url_helpers @@ -3560,11 +3721,14 @@ class TestHttpMethods < ActionDispatch::IntegrationTest lambda { |env| [ 200, { 'Content-Type' => 'text/plain' }, [response] ] } end - setup do + attr_reader :app + + def setup s = self - @app = ActionDispatch::Routing::RouteSet.new + routes = ActionDispatch::Routing::RouteSet.new + @app = RoutedRackApp.new routes - @app.draw do + routes.draw do (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789).each do |method| match '/' => s.simple_app(method), :via => method.underscore.to_sym end @@ -3595,7 +3759,8 @@ class TestUriPathEscaping < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end test 'escapes slash in generated path segment' do assert_equal '/a%20b%2Fc+d', segment_path(:segment => 'a b/c+d') @@ -3626,7 +3791,8 @@ class TestUnicodePaths < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end test 'recognizes unicode path' do get "/#{Rack::Utils.escape("ほげ")}" @@ -3657,7 +3823,8 @@ class TestMultipleNestedController < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end test "controller option which starts with '/' from multiple nested controller" do get "/foo/bar/baz" @@ -3676,7 +3843,8 @@ class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end test 'recognizes tilde path' do get "/~user" @@ -3703,7 +3871,8 @@ class TestRedirectInterpolation < ActionDispatch::IntegrationTest end end - def app; Routes end + APP = build_app Routes + def app; APP end test "redirect escapes interpolated parameters with redirect proc" do get "/foo/1%3E" @@ -3745,7 +3914,8 @@ class TestConstraintsAccessingParameters < ActionDispatch::IntegrationTest end end - def app; Routes end + APP = build_app Routes + def app; APP end test "parameters are reset between constraint checks" do get "/bar" @@ -3765,7 +3935,8 @@ class TestGlobRoutingMapper < ActionDispatch::IntegrationTest end #include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end def test_glob_constraint get "/dummy" @@ -3797,7 +3968,8 @@ class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end test 'enabled when not mounted and default_url_options is empty' do assert Routes.url_helpers.optimize_routes_generation? @@ -3869,7 +4041,8 @@ class TestNamedRouteUrlHelpers < ActionDispatch::IntegrationTest end end - def app; Routes end + APP = build_app Routes + def app; APP end include Routes.url_helpers @@ -3904,7 +4077,8 @@ class TestUrlConstraints < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end test "constraints are copied to defaults when using constraints method" do assert_equal 'http://admin.example.com/', admin_root_url @@ -3958,7 +4132,7 @@ class TestInvalidUrls < ActionDispatch::IntegrationTest set.draw do get "/bar/:id", :to => redirect("/foo/show/%{id}") get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show" - get "/foo(/:action(/:id))", :to => "test_invalid_urls/foo" + get "/foo(/:action(/:id))", :controller => "test_invalid_urls/foo" get "/:controller(/:action(/:id))" end @@ -3985,8 +4159,9 @@ class TestOptionalRootSegments < ActionDispatch::IntegrationTest end end + APP = build_app Routes def app - Routes + APP end include Routes.url_helpers @@ -4017,7 +4192,8 @@ class TestPortConstraints < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end def test_integer_port_constraints get 'http://www.example.com/integer' @@ -4065,7 +4241,8 @@ class TestFormatConstraints < ActionDispatch::IntegrationTest end include Routes.url_helpers - def app; Routes end + APP = build_app Routes + def app; APP end def test_string_format_constraints get 'http://www.example.com/string' @@ -4134,8 +4311,9 @@ class TestRouteDefaults < ActionDispatch::IntegrationTest end end + APP = build_app Routes def app - Routes + APP end include Routes.url_helpers @@ -4163,8 +4341,9 @@ class TestRackAppRouteGeneration < ActionDispatch::IntegrationTest end end + APP = build_app Routes def app - Routes + APP end include Routes.url_helpers @@ -4189,8 +4368,9 @@ class TestRedirectRouteGeneration < ActionDispatch::IntegrationTest end end + APP = build_app Routes def app - Routes + APP end include Routes.url_helpers @@ -4213,7 +4393,8 @@ class TestUrlGenerationErrors < ActionDispatch::IntegrationTest end end - def app; Routes end + APP = build_app Routes + def app; APP end include Routes.url_helpers diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb index 92544230b2..f7a06cfed4 100644 --- a/actionpack/test/dispatch/session/mem_cache_store_test.rb +++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb @@ -49,6 +49,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_response :success assert_equal 'foo: "bar"', response.body end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end def test_getting_nil_session_value @@ -57,6 +59,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_response :success assert_equal 'foo: nil', response.body end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end def test_getting_session_value_after_session_reset @@ -76,6 +80,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_response :success assert_equal 'foo: nil', response.body, "data for this session should have been obliterated from memcached" end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end def test_getting_from_nonexistent_session @@ -85,6 +91,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_equal 'foo: nil', response.body assert_nil cookies['_session_id'], "should only create session on write, not read" end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end def test_setting_session_value_after_session_reset @@ -106,6 +114,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_response :success assert_not_equal session_id, response.body end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end def test_getting_session_id @@ -119,6 +129,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_response :success assert_equal session_id, response.body, "should be able to read session id without accessing the session hash" end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end def test_deserializes_unloaded_class @@ -133,6 +145,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_response :success end end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end def test_doesnt_write_session_cookie_if_session_id_is_already_exists @@ -145,6 +159,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_response :success assert_equal nil, headers['Set-Cookie'], "should not resend the cookie again if session_id cookie is already exists" end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end def test_prevents_session_fixation @@ -160,6 +176,8 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest assert_response :success assert_not_equal session_id, cookies['_session_id'] end + rescue Dalli::RingError => ex + skip ex.message, ex.backtrace end rescue LoadError, RuntimeError, Dalli::DalliError $stderr.puts "Skipping MemCacheStoreTest tests. Start memcached and try again." diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb index 910ff8a80f..8f79e7bf9a 100644 --- a/actionpack/test/dispatch/url_generation_test.rb +++ b/actionpack/test/dispatch/url_generation_test.rb @@ -15,15 +15,19 @@ module TestUrlGeneration Routes.draw do get "/foo", :to => "my_route_generating#index", :as => :foo + resources :bars + mount MyRouteGeneratingController.action(:index), at: '/bar' end + APP = build_app Routes + def _routes Routes end def app - Routes + APP end test "generating URLS normally" do @@ -109,6 +113,22 @@ module TestUrlGeneration test "omit subdomain when key is blank" do assert_equal "http://example.com/foo", foo_url(subdomain: "") end + + test "generating URLs with trailing slashes" do + assert_equal "/bars.json", bars_path( + trailing_slash: true, + format: 'json' + ) + end + + test "generating URLS with querystring and trailing slashes" do + assert_equal "/bars.json?a=b", bars_path( + trailing_slash: true, + a: 'b', + format: 'json' + ) + end + end end diff --git a/actionpack/test/journey/path/pattern_test.rb b/actionpack/test/journey/path/pattern_test.rb index ce02104181..9dfdfc23ed 100644 --- a/actionpack/test/journey/path/pattern_test.rb +++ b/actionpack/test/journey/path/pattern_test.rb @@ -18,7 +18,7 @@ module ActionDispatch '/:controller/*foo/bar' => %r{\A/(#{x})/(.+)/bar\Z}, }.each do |path, expected| define_method(:"test_to_regexp_#{path}") do - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( path, { :controller => /.+/ }, ["/", ".", "?"] @@ -41,7 +41,7 @@ module ActionDispatch '/:controller/*foo/bar' => %r{\A/(#{x})/(.+)/bar}, }.each do |path, expected| define_method(:"test_to_non_anchored_regexp_#{path}") do - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( path, { :controller => /.+/ }, ["/", ".", "?"], @@ -65,7 +65,7 @@ module ActionDispatch '/:controller/*foo/bar' => %w{ controller foo }, }.each do |path, expected| define_method(:"test_names_#{path}") do - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( path, { :controller => /.+/ }, ["/", ".", "?"] @@ -75,12 +75,8 @@ module ActionDispatch end end - def test_to_raise_exception_with_bad_expression - assert_raise(ArgumentError, "Bad expression: []") { Pattern.new [] } - end - def test_to_regexp_with_extended_group - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( '/page/:name', { :name => / #ROFL @@ -101,13 +97,13 @@ module ActionDispatch ['/:foo(/:bar)', %w{ bar }], ['/:foo(/:bar)/:lol(/:baz)', %w{ bar baz }], ].each do |pattern, list| - path = Pattern.new pattern + path = Pattern.from_string pattern assert_equal list.sort, path.optional_names.sort end end def test_to_regexp_match_non_optional - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( '/:name', { :name => /\d+/ }, ["/", ".", "?"] @@ -118,7 +114,7 @@ module ActionDispatch end def test_to_regexp_with_group - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( '/page/:name', { :name => /(tender|love)/ }, ["/", ".", "?"] @@ -131,7 +127,7 @@ module ActionDispatch def test_ast_sets_regular_expressions requirements = { :name => /(tender|love)/, :value => /./ } - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( '/page/:name/:value', requirements, ["/", ".", "?"] @@ -148,7 +144,7 @@ module ActionDispatch end def test_match_data_with_group - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( '/page/:name', { :name => /(tender|love)/ }, ["/", ".", "?"] @@ -160,7 +156,7 @@ module ActionDispatch end def test_match_data_with_multi_group - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( '/page/:name/:id', { :name => /t(((ender|love)))()/ }, ["/", ".", "?"] @@ -175,7 +171,7 @@ module ActionDispatch def test_star_with_custom_re z = /\d+/ - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( '/page/*foo', { :foo => z }, ["/", ".", "?"] @@ -185,7 +181,7 @@ module ActionDispatch end def test_insensitive_regexp_with_group - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( '/page/:name/aaron', { :name => /(tender|love)/i }, ["/", ".", "?"] @@ -197,7 +193,7 @@ module ActionDispatch end def test_to_regexp_with_strexp - strexp = Router::Strexp.new('/:controller', { }, ["/", ".", "?"]) + strexp = Router::Strexp.build('/:controller', { }, ["/", ".", "?"]) path = Pattern.new strexp x = %r{\A/([^/.?]+)\Z} @@ -205,20 +201,20 @@ module ActionDispatch end def test_to_regexp_defaults - path = Pattern.new '/:controller(/:action(/:id))' + path = Pattern.from_string '/:controller(/:action(/:id))' expected = %r{\A/([^/.?]+)(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z} assert_equal expected, path.to_regexp end def test_failed_match - path = Pattern.new '/:controller(/:action(/:id(.:format)))' + path = Pattern.from_string '/:controller(/:action(/:id(.:format)))' uri = 'content' assert_not path =~ uri end def test_match_controller - path = Pattern.new '/:controller(/:action(/:id(.:format)))' + path = Pattern.from_string '/:controller(/:action(/:id(.:format)))' uri = '/content' match = path =~ uri @@ -230,7 +226,7 @@ module ActionDispatch end def test_match_controller_action - path = Pattern.new '/:controller(/:action(/:id(.:format)))' + path = Pattern.from_string '/:controller(/:action(/:id(.:format)))' uri = '/content/list' match = path =~ uri @@ -242,7 +238,7 @@ module ActionDispatch end def test_match_controller_action_id - path = Pattern.new '/:controller(/:action(/:id(.:format)))' + path = Pattern.from_string '/:controller(/:action(/:id(.:format)))' uri = '/content/list/10' match = path =~ uri @@ -254,7 +250,7 @@ module ActionDispatch end def test_match_literal - path = Path::Pattern.new "/books(/:action(.:format))" + path = Path::Pattern.from_string "/books(/:action(.:format))" uri = '/books' match = path =~ uri @@ -264,7 +260,7 @@ module ActionDispatch end def test_match_literal_with_action - path = Path::Pattern.new "/books(/:action(.:format))" + path = Path::Pattern.from_string "/books(/:action(.:format))" uri = '/books/list' match = path =~ uri @@ -274,7 +270,7 @@ module ActionDispatch end def test_match_literal_with_action_and_format - path = Path::Pattern.new "/books(/:action(.:format))" + path = Path::Pattern.from_string "/books(/:action(.:format))" uri = '/books/list.rss' match = path =~ uri diff --git a/actionpack/test/journey/route_test.rb b/actionpack/test/journey/route_test.rb index cbe6284714..21d867aca0 100644 --- a/actionpack/test/journey/route_test.rb +++ b/actionpack/test/journey/route_test.rb @@ -5,7 +5,7 @@ module ActionDispatch class TestRoute < ActiveSupport::TestCase def test_initialize app = Object.new - path = Path::Pattern.new '/:controller(/:action(/:id(.:format)))' + path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))' defaults = {} route = Route.new("name", app, path, {}, defaults) @@ -16,7 +16,7 @@ module ActionDispatch def test_route_adds_itself_as_memo app = Object.new - path = Path::Pattern.new '/:controller(/:action(/:id(.:format)))' + path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))' defaults = {} route = Route.new("name", app, path, {}, defaults) @@ -26,21 +26,21 @@ module ActionDispatch end def test_ip_address - path = Path::Pattern.new '/messages/:id(.:format)' + path = Path::Pattern.from_string '/messages/:id(.:format)' route = Route.new("name", nil, path, {:ip => '192.168.1.1'}, { :controller => 'foo', :action => 'bar' }) assert_equal '192.168.1.1', route.ip end def test_default_ip - path = Path::Pattern.new '/messages/:id(.:format)' + path = Path::Pattern.from_string '/messages/:id(.:format)' route = Route.new("name", nil, path, {}, { :controller => 'foo', :action => 'bar' }) assert_equal(//, route.ip) end def test_format_with_star - path = Path::Pattern.new '/:controller/*extra' + path = Path::Pattern.from_string '/:controller/*extra' route = Route.new("name", nil, path, {}, { :controller => 'foo', :action => 'bar' }) assert_equal '/foo/himom', route.format({ @@ -50,7 +50,7 @@ module ActionDispatch end def test_connects_all_match - path = Path::Pattern.new '/:controller(/:action(/:id(.:format)))' + path = Path::Pattern.from_string '/:controller(/:action(/:id(.:format)))' route = Route.new("name", nil, path, {:action => 'bar'}, { :controller => 'foo' }) assert_equal '/foo/bar/10', route.format({ @@ -61,21 +61,21 @@ module ActionDispatch end def test_extras_are_not_included_if_optional - path = Path::Pattern.new '/page/:id(/:action)' + path = Path::Pattern.from_string '/page/:id(/:action)' route = Route.new("name", nil, path, { }, { :action => 'show' }) assert_equal '/page/10', route.format({ :id => 10 }) end def test_extras_are_not_included_if_optional_with_parameter - path = Path::Pattern.new '(/sections/:section)/pages/:id' + path = Path::Pattern.from_string '(/sections/:section)/pages/:id' route = Route.new("name", nil, path, { }, { :action => 'show' }) assert_equal '/pages/10', route.format({:id => 10}) end def test_extras_are_not_included_if_optional_parameter_is_nil - path = Path::Pattern.new '(/sections/:section)/pages/:id' + path = Path::Pattern.from_string '(/sections/:section)/pages/:id' route = Route.new("name", nil, path, { }, { :action => 'show' }) assert_equal '/pages/10', route.format({:id => 10, :section => nil}) @@ -85,10 +85,10 @@ module ActionDispatch constraints = {:required_defaults => [:controller, :action]} defaults = {:controller=>"pages", :action=>"show"} - path = Path::Pattern.new "/page/:id(/:action)(.:format)" + path = Path::Pattern.from_string "/page/:id(/:action)(.:format)" specific = Route.new "name", nil, path, constraints, defaults - path = Path::Pattern.new "/:controller(/:action(/:id))(.:format)" + path = Path::Pattern.from_string "/:controller(/:action(/:id))(.:format)" generic = Route.new "name", nil, path, constraints knowledge = {:id=>20, :controller=>"pages", :action=>"show"} diff --git a/actionpack/test/journey/router/strexp_test.rb b/actionpack/test/journey/router/strexp_test.rb deleted file mode 100644 index 7ccdfb7b4d..0000000000 --- a/actionpack/test/journey/router/strexp_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'abstract_unit' - -module ActionDispatch - module Journey - class Router - class TestStrexp < ActiveSupport::TestCase - def test_many_names - exp = Strexp.new( - "/:controller(/:action(/:id(.:format)))", - {:controller=>/.+?/}, - ["/", ".", "?"], - true) - - assert_equal ["controller", "action", "id", "format"], exp.names - end - - def test_names - { - "/bar(.:format)" => %w{ format }, - ":format" => %w{ format }, - ":format-" => %w{ format }, - ":format0" => %w{ format0 }, - ":format1,:format2" => %w{ format1 format2 }, - }.each do |string, expected| - exp = Strexp.new(string, {}, ["/", ".", "?"]) - assert_equal expected, exp.names - end - end - end - end - end -end diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb index e54b64e0f3..2e7e8e1bea 100644 --- a/actionpack/test/journey/router_test.rb +++ b/actionpack/test/journey/router_test.rb @@ -4,24 +4,15 @@ require 'abstract_unit' module ActionDispatch module Journey class TestRouter < ActiveSupport::TestCase - # TODO : clean up routing tests so we don't need this hack - class StubDispatcher < Routing::RouteSet::Dispatcher; end - attr_reader :routes def setup - @app = StubDispatcher.new + @app = Routing::RouteSet::Dispatcher.new({}) @routes = Routes.new - @router = Router.new(@routes, {}) + @router = Router.new(@routes) @formatter = Formatter.new(@routes) end - def test_request_class_reader - klass = Object.new - router = Router.new(routes, :request_class => klass) - assert_equal klass, router.request_class - end - class FakeRequestFeeler < Struct.new(:env, :called) def new env self.env = env @@ -39,33 +30,33 @@ module ActionDispatch end def test_dashes - router = Router.new(routes, {}) + router = Router.new(routes) - exp = Router::Strexp.new '/foo-bar-baz', {}, ['/.?'] + exp = Router::Strexp.build '/foo-bar-baz', {}, ['/.?'] path = Path::Pattern.new exp routes.add_route nil, path, {}, {:id => nil}, {} env = rails_env 'PATH_INFO' => '/foo-bar-baz' called = false - router.recognize(env) do |r, _, params| + router.recognize(env) do |r, params| called = true end assert called end def test_unicode - router = Router.new(routes, {}) + router = Router.new(routes) #match the escaped version of /ほげ - exp = Router::Strexp.new '/%E3%81%BB%E3%81%92', {}, ['/.?'] + exp = Router::Strexp.build '/%E3%81%BB%E3%81%92', {}, ['/.?'] path = Path::Pattern.new exp routes.add_route nil, path, {}, {:id => nil}, {} env = rails_env 'PATH_INFO' => '/%E3%81%BB%E3%81%92' called = false - router.recognize(env) do |r, _, params| + router.recognize(env) do |r, params| called = true end assert called @@ -73,17 +64,17 @@ module ActionDispatch def test_request_class_and_requirements_success klass = FakeRequestFeeler.new nil - router = Router.new(routes, {:request_class => klass }) + router = Router.new(routes) requirements = { :hello => /world/ } - exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?'] + exp = Router::Strexp.build '/foo(/:id)', {}, ['/.?'] path = Path::Pattern.new exp routes.add_route nil, path, requirements, {:id => nil}, {} - env = rails_env 'PATH_INFO' => '/foo/10' - router.recognize(env) do |r, _, params| + env = rails_env({'PATH_INFO' => '/foo/10'}, klass) + router.recognize(env) do |r, params| assert_equal({:id => '10'}, params) end @@ -93,17 +84,17 @@ module ActionDispatch def test_request_class_and_requirements_fail klass = FakeRequestFeeler.new nil - router = Router.new(routes, {:request_class => klass }) + router = Router.new(routes) requirements = { :hello => /mom/ } - exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?'] + exp = Router::Strexp.build '/foo(/:id)', {}, ['/.?'] path = Path::Pattern.new exp router.routes.add_route nil, path, requirements, {:id => nil}, {} - env = rails_env 'PATH_INFO' => '/foo/10' - router.recognize(env) do |r, _, params| + env = rails_env({'PATH_INFO' => '/foo/10'}, klass) + router.recognize(env) do |r, params| flunk 'route should not be found' end @@ -111,24 +102,29 @@ module ActionDispatch assert_equal env.env, klass.env end - class CustomPathRequest < Router::NullReq + class CustomPathRequest < ActionDispatch::Request def path_info env['custom.path_info'] end + + def path_info=(x) + env['custom.path_info'] = x + end end def test_request_class_overrides_path_info - router = Router.new(routes, {:request_class => CustomPathRequest }) + router = Router.new(routes) - exp = Router::Strexp.new '/bar', {}, ['/.?'] + exp = Router::Strexp.build '/bar', {}, ['/.?'] path = Path::Pattern.new exp routes.add_route nil, path, {}, {}, {} - env = rails_env 'PATH_INFO' => '/foo', 'custom.path_info' => '/bar' + env = rails_env({'PATH_INFO' => '/foo', + 'custom.path_info' => '/bar'}, CustomPathRequest) recognized = false - router.recognize(env) do |r, _, params| + router.recognize(env) do |r, params| recognized = true end @@ -137,14 +133,14 @@ module ActionDispatch def test_regexp_first_precedence add_routes @router, [ - Router::Strexp.new("/whois/:domain", {:domain => /\w+\.[\w\.]+/}, ['/', '.', '?']), - Router::Strexp.new("/whois/:id(.:format)", {}, ['/', '.', '?']) + Router::Strexp.build("/whois/:domain", {:domain => /\w+\.[\w\.]+/}, ['/', '.', '?']), + Router::Strexp.build("/whois/:id(.:format)", {}, ['/', '.', '?']) ] env = rails_env 'PATH_INFO' => '/whois/example.com' list = [] - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| list << r end assert_equal 2, list.length @@ -156,50 +152,50 @@ module ActionDispatch def test_required_parts_verified_are_anchored add_routes @router, [ - Router::Strexp.new("/foo/:id", { :id => /\d/ }, ['/', '.', '?'], false) + Router::Strexp.build("/foo/:id", { :id => /\d/ }, ['/', '.', '?'], false) ] assert_raises(ActionController::UrlGenerationError) do - @formatter.generate(:path_info, nil, { :id => '10' }, { }) + @formatter.generate(nil, { :id => '10' }, { }) end end def test_required_parts_are_verified_when_building add_routes @router, [ - Router::Strexp.new("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false) + Router::Strexp.build("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false) ] - path, _ = @formatter.generate(:path_info, nil, { :id => '10' }, { }) + path, _ = @formatter.generate(nil, { :id => '10' }, { }) assert_equal '/foo/10', path assert_raises(ActionController::UrlGenerationError) do - @formatter.generate(:path_info, nil, { :id => 'aa' }, { }) + @formatter.generate(nil, { :id => 'aa' }, { }) end end def test_only_required_parts_are_verified add_routes @router, [ - Router::Strexp.new("/foo(/:id)", {:id => /\d/}, ['/', '.', '?'], false) + Router::Strexp.build("/foo(/:id)", {:id => /\d/}, ['/', '.', '?'], false) ] - path, _ = @formatter.generate(:path_info, nil, { :id => '10' }, { }) + path, _ = @formatter.generate(nil, { :id => '10' }, { }) assert_equal '/foo/10', path - path, _ = @formatter.generate(:path_info, nil, { }, { }) + path, _ = @formatter.generate(nil, { }, { }) assert_equal '/foo', path - path, _ = @formatter.generate(:path_info, nil, { :id => 'aa' }, { }) + path, _ = @formatter.generate(nil, { :id => 'aa' }, { }) assert_equal '/foo/aa', path end def test_knows_what_parts_are_missing_from_named_route route_name = "gorby_thunderhorse" - pattern = Router::Strexp.new("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false) + pattern = Router::Strexp.build("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false) path = Path::Pattern.new pattern @router.routes.add_route nil, path, {}, {}, route_name error = assert_raises(ActionController::UrlGenerationError) do - @formatter.generate(:path_info, route_name, { }, { }) + @formatter.generate(route_name, { }, { }) end assert_match(/missing required keys: \[:id\]/, error.message) @@ -207,42 +203,43 @@ module ActionDispatch def test_X_Cascade add_routes @router, [ "/messages(.:format)" ] - resp = @router.call({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' }) + resp = @router.serve(rails_env({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' })) assert_equal ['Not Found'], resp.last assert_equal 'pass', resp[1]['X-Cascade'] assert_equal 404, resp.first end def test_clear_trailing_slash_from_script_name_on_root_unanchored_routes - strexp = Router::Strexp.new("/", {}, ['/', '.', '?'], false) - path = Path::Pattern.new strexp + route_set = Routing::RouteSet.new + mapper = Routing::Mapper.new route_set + app = lambda { |env| [200, {}, ['success!']] } - @router.routes.add_route(app, path, {}, {}, {}) + mapper.get '/weblog', :to => app env = rack_env('SCRIPT_NAME' => '', 'PATH_INFO' => '/weblog') - resp = @router.call(env) + resp = route_set.call env assert_equal ['success!'], resp.last assert_equal '', env['SCRIPT_NAME'] end def test_defaults_merge_correctly - path = Path::Pattern.new '/foo(/:id)' + path = Path::Pattern.from_string '/foo(/:id)' @router.routes.add_route nil, path, {}, {:id => nil}, {} env = rails_env 'PATH_INFO' => '/foo/10' - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| assert_equal({:id => '10'}, params) end env = rails_env 'PATH_INFO' => '/foo' - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| assert_equal({:id => nil}, params) end end def test_recognize_with_unbound_regexp add_routes @router, [ - Router::Strexp.new("/foo", { }, ['/', '.', '?'], false) + Router::Strexp.build("/foo", { }, ['/', '.', '?'], false) ] env = rails_env 'PATH_INFO' => '/foo/bar' @@ -255,7 +252,7 @@ module ActionDispatch def test_bound_regexp_keeps_path_info add_routes @router, [ - Router::Strexp.new("/foo", { }, ['/', '.', '?'], true) + Router::Strexp.build("/foo", { }, ['/', '.', '?'], true) ] env = rails_env 'PATH_INFO' => '/foo' @@ -287,14 +284,14 @@ module ActionDispatch def test_required_part_in_recall add_routes @router, [ "/messages/:a/:b" ] - path, _ = @formatter.generate(:path_info, nil, { :a => 'a' }, { :b => 'b' }) + path, _ = @formatter.generate(nil, { :a => 'a' }, { :b => 'b' }) assert_equal "/messages/a/b", path end def test_splat_in_recall add_routes @router, [ "/*path" ] - path, _ = @formatter.generate(:path_info, nil, { }, { :path => 'b' }) + path, _ = @formatter.generate(nil, { }, { :path => 'b' }) assert_equal "/b", path end @@ -304,35 +301,35 @@ module ActionDispatch "/messages/:id(.:format)" ] - path, _ = @formatter.generate(:path_info, nil, { :id => 10 }, { :action => 'index' }) + path, _ = @formatter.generate(nil, { :id => 10 }, { :action => 'index' }) assert_equal "/messages/index/10", path end def test_nil_path_parts_are_ignored - path = Path::Pattern.new "/:controller(/:action(.:format))" + path = Path::Pattern.from_string "/:controller(/:action(.:format))" @router.routes.add_route @app, path, {}, {}, {} params = { :controller => "tasks", :format => nil } extras = { :action => 'lol' } - path, _ = @formatter.generate(:path_info, nil, params, extras) + path, _ = @formatter.generate(nil, params, extras) assert_equal '/tasks', path end def test_generate_slash params = [ [:controller, "tasks"], [:action, "show"] ] - str = Router::Strexp.new("/", Hash[params], ['/', '.', '?'], true) + str = Router::Strexp.build("/", Hash[params], ['/', '.', '?'], true) path = Path::Pattern.new str @router.routes.add_route @app, path, {}, {}, {} - path, _ = @formatter.generate(:path_info, nil, Hash[params], {}) + path, _ = @formatter.generate(nil, Hash[params], {}) assert_equal '/', path end def test_generate_calls_param_proc - path = Path::Pattern.new '/:controller(/:action)' + path = Path::Pattern.from_string '/:controller(/:action)' @router.routes.add_route @app, path, {}, {}, {} parameterized = [] @@ -340,7 +337,6 @@ module ActionDispatch [:action, "show"] ] @formatter.generate( - :path_info, nil, Hash[params], {}, @@ -350,31 +346,31 @@ module ActionDispatch end def test_generate_id - path = Path::Pattern.new '/:controller(/:action)' + path = Path::Pattern.from_string '/:controller(/:action)' @router.routes.add_route @app, path, {}, {}, {} path, params = @formatter.generate( - :path_info, nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {}) + nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {}) assert_equal '/tasks/show', path assert_equal({:id => 1}, params) end def test_generate_escapes - path = Path::Pattern.new '/:controller(/:action)' + path = Path::Pattern.from_string '/:controller(/:action)' @router.routes.add_route @app, path, {}, {}, {} - path, _ = @formatter.generate(:path_info, - nil, { :controller => "tasks", + path, _ = @formatter.generate(nil, + { :controller => "tasks", :action => "a/b c+d", }, {}) assert_equal '/tasks/a%2Fb%20c+d', path end def test_generate_escapes_with_namespaced_controller - path = Path::Pattern.new '/:controller(/:action)' + path = Path::Pattern.from_string '/:controller(/:action)' @router.routes.add_route @app, path, {}, {}, {} - path, _ = @formatter.generate(:path_info, + path, _ = @formatter.generate( nil, { :controller => "admin/tasks", :action => "a/b c+d", }, {}) @@ -382,10 +378,10 @@ module ActionDispatch end def test_generate_extra_params - path = Path::Pattern.new '/:controller(/:action)' + path = Path::Pattern.from_string '/:controller(/:action)' @router.routes.add_route @app, path, {}, {}, {} - path, params = @formatter.generate(:path_info, + path, params = @formatter.generate( nil, { :id => 1, :controller => "tasks", :action => "show", @@ -396,10 +392,10 @@ module ActionDispatch end def test_generate_uses_recall_if_needed - path = Path::Pattern.new '/:controller(/:action(/:id))' + path = Path::Pattern.from_string '/:controller(/:action(/:id))' @router.routes.add_route @app, path, {}, {}, {} - path, params = @formatter.generate(:path_info, + path, params = @formatter.generate( nil, {:controller =>"tasks", :id => 10}, {:action =>"index"}) @@ -408,10 +404,10 @@ module ActionDispatch end def test_generate_with_name - path = Path::Pattern.new '/:controller(/:action)' + path = Path::Pattern.from_string '/:controller(/:action)' @router.routes.add_route @app, path, {}, {}, {} - path, params = @formatter.generate(:path_info, + path, params = @formatter.generate( "tasks", {:controller=>"tasks"}, {:controller=>"tasks", :action=>"index"}) @@ -425,14 +421,14 @@ module ActionDispatch '/content/show/10' => { :controller => 'content', :action => 'show', :id => "10" }, }.each do |request_path, expected| define_method("test_recognize_#{expected.keys.map(&:to_s).join('_')}") do - path = Path::Pattern.new "/:controller(/:action(/:id))" + path = Path::Pattern.from_string "/:controller(/:action(/:id))" app = Object.new route = @router.routes.add_route(app, path, {}, {}, {}) env = rails_env 'PATH_INFO' => request_path called = false - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| assert_equal route, r assert_equal(expected, params) called = true @@ -447,14 +443,14 @@ module ActionDispatch :splat => ['/segment/a/b%20c+d', { :segment => 'segment', :splat => 'a/b c+d' }] }.each do |name, (request_path, expected)| define_method("test_recognize_#{name}") do - path = Path::Pattern.new '/:segment/*splat' + path = Path::Pattern.from_string '/:segment/*splat' app = Object.new route = @router.routes.add_route(app, path, {}, {}, {}) env = rails_env 'PATH_INFO' => request_path called = false - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| assert_equal route, r assert_equal(expected, params) called = true @@ -465,7 +461,7 @@ module ActionDispatch end def test_namespaced_controller - strexp = Router::Strexp.new( + strexp = Router::Strexp.build( "/:controller(/:action(/:id))", { :controller => /.+?/ }, ["/", ".", "?"] @@ -482,7 +478,7 @@ module ActionDispatch :id => '10' } - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| assert_equal route, r assert_equal(expected, params) called = true @@ -491,14 +487,14 @@ module ActionDispatch end def test_recognize_literal - path = Path::Pattern.new "/books(/:action(.:format))" + path = Path::Pattern.from_string "/books(/:action(.:format))" app = Object.new route = @router.routes.add_route(app, path, {}, {:controller => 'books'}) env = rails_env 'PATH_INFO' => '/books/list.rss' expected = { :controller => 'books', :action => 'list', :format => 'rss' } called = false - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| assert_equal route, r assert_equal(expected, params) called = true @@ -508,7 +504,7 @@ module ActionDispatch end def test_recognize_head_request_as_get_route - path = Path::Pattern.new "/books(/:action(.:format))" + path = Path::Pattern.from_string "/books(/:action(.:format))" app = Object.new conditions = { :request_method => 'GET' @@ -519,7 +515,7 @@ module ActionDispatch "REQUEST_METHOD" => "HEAD" called = false - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| called = true end @@ -527,7 +523,7 @@ module ActionDispatch end def test_recognize_cares_about_verbs - path = Path::Pattern.new "/books(/:action(.:format))" + path = Path::Pattern.from_string "/books(/:action(.:format))" app = Object.new conditions = { :request_method => 'GET' @@ -543,7 +539,7 @@ module ActionDispatch "REQUEST_METHOD" => "POST" called = false - @router.recognize(env) do |r, _, params| + @router.recognize(env) do |r, params| assert_equal post, r called = true end @@ -555,15 +551,17 @@ module ActionDispatch def add_routes router, paths paths.each do |path| - path = Path::Pattern.new path + if String === path + path = Path::Pattern.from_string path + else + path = Path::Pattern.new path + end router.routes.add_route @app, path, {}, {}, {} end end - RailsEnv = Struct.new(:env) - - def rails_env env - RailsEnv.new rack_env env + def rails_env env, klass = ActionDispatch::Request + klass.new env end def rack_env env diff --git a/actionpack/test/journey/routes_test.rb b/actionpack/test/journey/routes_test.rb index 25e0321d31..a4efc82b8c 100644 --- a/actionpack/test/journey/routes_test.rb +++ b/actionpack/test/journey/routes_test.rb @@ -5,7 +5,7 @@ module ActionDispatch class TestRoutes < ActiveSupport::TestCase def test_clear routes = Routes.new - exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?'] + exp = Router::Strexp.build '/foo(/:id)', {}, ['/.?'] path = Path::Pattern.new exp requirements = { :hello => /world/ } @@ -18,7 +18,7 @@ module ActionDispatch def test_ast routes = Routes.new - path = Path::Pattern.new '/hello' + path = Path::Pattern.from_string '/hello' routes.add_route nil, path, {}, {}, {} ast = routes.ast @@ -28,7 +28,7 @@ module ActionDispatch def test_simulator_changes routes = Routes.new - path = Path::Pattern.new '/hello' + path = Path::Pattern.from_string '/hello' routes.add_route nil, path, {}, {}, {} sim = routes.simulator @@ -40,8 +40,8 @@ module ActionDispatch #def add_route app, path, conditions, defaults, name = nil routes = Routes.new - one = Path::Pattern.new '/hello' - two = Path::Pattern.new '/aaron' + one = Path::Pattern.from_string '/hello' + two = Path::Pattern.from_string '/aaron' routes.add_route nil, one, {}, {}, 'aaron' routes.add_route nil, two, {}, {}, 'aaron' |