1 require 'abstract_unit'
3 # FIXME: crashes Ruby 1.9
4 class FilterTest
< Test
::Unit::TestCase
5 class TestController
< ActionController
::Base
6 before_filter
:ensure_login
10 render
:inline => "ran action"
16 @ran_filter << "ensure_login"
20 @ran_after_filter ||= []
21 @ran_after_filter << "clean_up"
25 class ChangingTheRequirementsController
< TestController
26 before_filter
:ensure_login, :except => [:go_wild]
29 render
:text => "gobble"
33 class TestMultipleFiltersController
< ActionController
::Base
39 define_method
"fail_#{i}" do
40 render
:text => i
.to_s
46 define_method
"try_#{i}" do
47 instance_variable_set
:@try, i
48 if action_name
== "fail_#{i}"
55 class RenderingController
< ActionController
::Base
56 before_filter
:render_something_else
60 render
:inline => "ran action"
64 def render_something_else
65 render
:inline => "something else"
69 class ConditionalFilterController
< ActionController
::Base
71 render
:inline => "ran action"
75 render
:inline => "ran action"
78 def show_without_filter
79 render
:inline => "ran action without filter"
85 @ran_filter << "ensure_login"
90 @ran_filter << "clean_up_tmp"
93 def rescue_action(e
) raise(e
) end
96 class ConditionalCollectionFilterController
< ConditionalFilterController
97 before_filter
:ensure_login, :except => [ :show_without_filter, :another_action ]
100 class OnlyConditionSymController
< ConditionalFilterController
101 before_filter
:ensure_login, :only => :show
104 class ExceptConditionSymController
< ConditionalFilterController
105 before_filter
:ensure_login, :except => :show_without_filter
108 class BeforeAndAfterConditionController
< ConditionalFilterController
109 before_filter
:ensure_login, :only => :show
110 after_filter
:clean_up_tmp, :only => :show
113 class OnlyConditionProcController
< ConditionalFilterController
114 before_filter(:only => :show) {|c
| c
.instance_variable_set(:"@ran_proc_filter", true) }
117 class ExceptConditionProcController
< ConditionalFilterController
118 before_filter(:except => :show_without_filter) {|c
| c
.instance_variable_set(:"@ran_proc_filter", true) }
121 class ConditionalClassFilter
122 def self.filter(controller
) controller
.instance_variable_set(:"@ran_class_filter", true) end
125 class OnlyConditionClassController
< ConditionalFilterController
126 before_filter ConditionalClassFilter
, :only => :show
129 class ExceptConditionClassController
< ConditionalFilterController
130 before_filter ConditionalClassFilter
, :except => :show_without_filter
133 class AnomolousYetValidConditionController
< ConditionalFilterController
134 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)}
137 class ConditionalOptionsFilter
< ConditionalFilterController
138 before_filter
:ensure_login, :if => Proc
.new
{ |c
| true }
139 before_filter
:clean_up_tmp, :if => Proc
.new
{ |c
| false }
142 class EmptyFilterChainController
< TestController
143 self.filter_chain
.clear
145 @action_executed = true
146 render
:text => "yawp!"
150 class PrependingController
< TestController
151 prepend_before_filter
:wonderful_life
152 # skip_before_filter :fire_flash
157 @ran_filter << "wonderful_life"
161 class SkippingAndLimitedController
< TestController
162 skip_before_filter
:ensure_login
163 before_filter
:ensure_login, :only => :index
173 class SkippingAndReorderingController
< TestController
174 skip_before_filter
:ensure_login
175 before_filter
:find_record
176 before_filter
:ensure_login
181 @ran_filter << "find_record"
185 class ConditionalSkippingController
< TestController
186 skip_before_filter
:ensure_login, :only => [ :login ]
187 skip_after_filter
:clean_up, :only => [ :login ]
189 before_filter
:find_user, :only => [ :change_password ]
192 render
:inline => "ran action"
196 render
:inline => "ran action"
202 @ran_filter << "find_user"
206 class ConditionalParentOfConditionalSkippingController
< ConditionalFilterController
207 before_filter
:conditional_in_parent, :only => [:show, :another_action]
208 after_filter
:conditional_in_parent, :only => [:show, :another_action]
212 def conditional_in_parent
214 @ran_filter << 'conditional_in_parent'
218 class ChildOfConditionalParentController
< ConditionalParentOfConditionalSkippingController
219 skip_before_filter
:conditional_in_parent, :only => :another_action
220 skip_after_filter
:conditional_in_parent, :only => :another_action
223 class AnotherChildOfConditionalParentController
< ConditionalParentOfConditionalSkippingController
224 skip_before_filter
:conditional_in_parent, :only => :show
227 class ProcController
< PrependingController
228 before_filter(proc
{ |c
| c
.instance_variable_set(:"@ran_proc_filter", true) })
231 class ImplicitProcController
< PrependingController
232 before_filter
{ |c
| c
.instance_variable_set(:"@ran_proc_filter", true) }
236 def self.filter(controller
)
237 controller
.instance_variable_set(:"@was_audited", true)
242 def before(controller
)
243 @execution_log = "before"
244 controller
.class.execution_log
<< " before aroundfilter " if controller
.respond_to
? :execution_log
245 controller
.instance_variable_set(:"@before_ran", true)
248 def after(controller
)
249 controller
.instance_variable_set(:"@execution_log", @execution_log + " and after")
250 controller
.instance_variable_set(:"@after_ran", true)
251 controller
.class.execution_log
<< " after aroundfilter " if controller
.respond_to
? :execution_log
255 class AppendedAroundFilter
256 def before(controller
)
257 controller
.class.execution_log
<< " before appended aroundfilter "
260 def after(controller
)
261 controller
.class.execution_log
<< " after appended aroundfilter "
265 class AuditController
< ActionController
::Base
266 before_filter(AuditFilter
)
269 render
:text => "hello"
273 class AroundFilterController
< PrependingController
274 around_filter AroundFilter
.new
277 class BeforeAfterClassFilterController
< PrependingController
279 filter
= AroundFilter
.new
285 class MixedFilterController
< PrependingController
286 cattr_accessor
:execution_log
292 before_filter
{ |c
| c
.class.execution_log
<< " before procfilter " }
293 prepend_around_filter AroundFilter
.new
295 after_filter
{ |c
| c
.class.execution_log
<< " after procfilter " }
296 append_around_filter AppendedAroundFilter
.new
299 class MixedSpecializationController
< ActionController
::Base
300 class OutOfOrder
< StandardError
; end
303 before_filter
:second, :only => :foo
306 render
:text => 'foo'
310 render
:text => 'bar'
319 raise OutOfOrder
unless @first
323 class DynamicDispatchController
< ActionController
::Base
324 before_filter
:choose
326 %w(foo bar baz
).each
do |action
|
327 define_method(action
) { render
:text => action
}
332 self.action_name
= params
[:choose]
336 class PrependingBeforeAndAfterController
< ActionController
::Base
337 prepend_before_filter
:before_all
338 prepend_after_filter
:after_all
339 before_filter
:between_before_all_and_after_all
343 @ran_filter << 'before_all'
348 @ran_filter << 'after_all'
351 def between_before_all_and_after_all
353 @ran_filter << 'between_before_all_and_after_all'
356 render
:text => 'hello'
360 class ErrorToRescue
< Exception
; end
362 class RescuingAroundFilterWithBlock
363 def filter(controller
)
366 rescue ErrorToRescue
=> ex
367 controller
.__send__
:render, :text => "I rescued this: #{ex.inspect}"
372 class RescuedController
< ActionController
::Base
373 around_filter RescuingAroundFilterWithBlock
.new
376 raise ErrorToRescue
.new("Something made the bad noise.")
380 def rescue_action(exception
)
385 class NonYieldingAroundFilterController
< ActionController
::Base
387 before_filter
:filter_one
388 around_filter
:non_yielding_filter
389 before_filter
:filter_two
390 after_filter
:filter_three
393 render
:inline => "index"
396 #make sure the controller complains
397 def rescue_action(e
); raise e
; end
403 @filters << "filter_one"
407 @filters << "filter_two"
410 def non_yielding_filter
411 @filters << "zomg it didn't yield"
416 @filters << "filter_three"
421 def test_non_yielding_around_filters_not_returning_false_do_not_raise
422 controller
= NonYieldingAroundFilterController
.new
423 controller
.instance_variable_set
"@filter_return_value", true
424 assert_nothing_raised
do
425 test_process(controller
, "index")
429 def test_non_yielding_around_filters_returning_false_do_not_raise
430 controller
= NonYieldingAroundFilterController
.new
431 controller
.instance_variable_set
"@filter_return_value", false
432 assert_nothing_raised
do
433 test_process(controller
, "index")
437 def test_after_filters_are_not_run_if_around_filter_returns_false
438 controller
= NonYieldingAroundFilterController
.new
439 controller
.instance_variable_set
"@filter_return_value", false
440 test_process(controller
, "index")
441 assert_equal
["filter_one", "zomg it didn't yield"], controller
.assigns
['filters']
444 def test_after_filters_are_not_run_if_around_filter_does_not_yield
445 controller
= NonYieldingAroundFilterController
.new
446 controller
.instance_variable_set
"@filter_return_value", true
447 test_process(controller
, "index")
448 assert_equal
["filter_one", "zomg it didn't yield"], controller
.assigns
['filters']
451 def test_empty_filter_chain
452 assert_equal
0, EmptyFilterChainController
.filter_chain
.size
453 assert
test_process(EmptyFilterChainController
).template
.assigns
['action_executed']
456 def test_added_filter_to_inheritance_graph
457 assert_equal
[ :ensure_login ], TestController
.before_filters
460 def test_base_class_in_isolation
461 assert_equal
[ ], ActionController
::Base.before_filters
464 def test_prepending_filter
465 assert_equal
[ :wonderful_life, :ensure_login ], PrependingController
.before_filters
468 def test_running_filters
469 assert_equal
%w( wonderful_life ensure_login
), test_process(PrependingController
).template
.assigns
["ran_filter"]
472 def test_running_filters_with_proc
473 assert
test_process(ProcController
).template
.assigns
["ran_proc_filter"]
476 def test_running_filters_with_implicit_proc
477 assert
test_process(ImplicitProcController
).template
.assigns
["ran_proc_filter"]
480 def test_running_filters_with_class
481 assert
test_process(AuditController
).template
.assigns
["was_audited"]
484 def test_running_anomolous_yet_valid_condition_filters
485 response
= test_process(AnomolousYetValidConditionController
)
486 assert_equal
%w( ensure_login
), response
.template
.assigns
["ran_filter"]
487 assert response
.template
.assigns
["ran_class_filter"]
488 assert response
.template
.assigns
["ran_proc_filter1"]
489 assert response
.template
.assigns
["ran_proc_filter2"]
491 response
= test_process(AnomolousYetValidConditionController
, "show_without_filter")
492 assert_equal
nil, response
.template
.assigns
["ran_filter"]
493 assert
!response
.template
.assigns
["ran_class_filter"]
494 assert
!response
.template
.assigns
["ran_proc_filter1"]
495 assert
!response
.template
.assigns
["ran_proc_filter2"]
498 def test_running_conditional_options
499 response
= test_process(ConditionalOptionsFilter
)
500 assert_equal
%w( ensure_login
), response
.template
.assigns
["ran_filter"]
503 def test_running_collection_condition_filters
504 assert_equal
%w( ensure_login
), test_process(ConditionalCollectionFilterController
).template
.assigns
["ran_filter"]
505 assert_equal
nil, test_process(ConditionalCollectionFilterController
, "show_without_filter").template
.assigns
["ran_filter"]
506 assert_equal
nil, test_process(ConditionalCollectionFilterController
, "another_action").template
.assigns
["ran_filter"]
509 def test_running_only_condition_filters
510 assert_equal
%w( ensure_login
), test_process(OnlyConditionSymController
).template
.assigns
["ran_filter"]
511 assert_equal
nil, test_process(OnlyConditionSymController
, "show_without_filter").template
.assigns
["ran_filter"]
513 assert
test_process(OnlyConditionProcController
).template
.assigns
["ran_proc_filter"]
514 assert
!test_process(OnlyConditionProcController
, "show_without_filter").template
.assigns
["ran_proc_filter"]
516 assert
test_process(OnlyConditionClassController
).template
.assigns
["ran_class_filter"]
517 assert
!test_process(OnlyConditionClassController
, "show_without_filter").template
.assigns
["ran_class_filter"]
520 def test_running_except_condition_filters
521 assert_equal
%w( ensure_login
), test_process(ExceptConditionSymController
).template
.assigns
["ran_filter"]
522 assert_equal
nil, test_process(ExceptConditionSymController
, "show_without_filter").template
.assigns
["ran_filter"]
524 assert
test_process(ExceptConditionProcController
).template
.assigns
["ran_proc_filter"]
525 assert
!test_process(ExceptConditionProcController
, "show_without_filter").template
.assigns
["ran_proc_filter"]
527 assert
test_process(ExceptConditionClassController
).template
.assigns
["ran_class_filter"]
528 assert
!test_process(ExceptConditionClassController
, "show_without_filter").template
.assigns
["ran_class_filter"]
531 def test_running_before_and_after_condition_filters
532 assert_equal
%w( ensure_login clean_up_tmp
), test_process(BeforeAndAfterConditionController
).template
.assigns
["ran_filter"]
533 assert_equal
nil, test_process(BeforeAndAfterConditionController
, "show_without_filter").template
.assigns
["ran_filter"]
536 def test_around_filter
537 controller
= test_process(AroundFilterController
)
538 assert controller
.template
.assigns
["before_ran"]
539 assert controller
.template
.assigns
["after_ran"]
542 def test_before_after_class_filter
543 controller
= test_process(BeforeAfterClassFilterController
)
544 assert controller
.template
.assigns
["before_ran"]
545 assert controller
.template
.assigns
["after_ran"]
548 def test_having_properties_in_around_filter
549 controller
= test_process(AroundFilterController
)
550 assert_equal
"before and after", controller
.template
.assigns
["execution_log"]
553 def test_prepending_and_appending_around_filter
554 controller
= test_process(MixedFilterController
)
555 assert_equal
" before aroundfilter before procfilter before appended aroundfilter " +
556 " after appended aroundfilter after aroundfilter after procfilter ",
557 MixedFilterController
.execution_log
560 def test_rendering_breaks_filtering_chain
561 response
= test_process(RenderingController
)
562 assert_equal
"something else", response
.body
563 assert
!response
.template
.assigns
["ran_action"]
566 def test_filters_with_mixed_specialization_run_in_order
567 assert_nothing_raised
do
568 response
= test_process(MixedSpecializationController
, 'bar')
569 assert_equal
'bar', response
.body
572 assert_nothing_raised
do
573 response
= test_process(MixedSpecializationController
, 'foo')
574 assert_equal
'foo', response
.body
578 def test_dynamic_dispatch
579 %w(foo bar baz
).each
do |action
|
580 request
= ActionController
::TestRequest.new
581 request
.query_parameters
[:choose] = action
582 response
= DynamicDispatchController
.process(request
, ActionController
::TestResponse.new
)
583 assert_equal action
, response
.body
587 def test_running_prepended_before_and_after_filter
588 assert_equal
3, PrependingBeforeAndAfterController
.filter_chain
.length
589 response
= test_process(PrependingBeforeAndAfterController
)
590 assert_equal
%w( before_all between_before_all_and_after_all after_all
), response
.template
.assigns
["ran_filter"]
593 def test_skipping_and_limiting_controller
594 assert_equal
%w( ensure_login
), test_process(SkippingAndLimitedController
, "index").template
.assigns
["ran_filter"]
595 assert_nil
test_process(SkippingAndLimitedController
, "public").template
.assigns
["ran_filter"]
598 def test_skipping_and_reordering_controller
599 assert_equal
%w( find_record ensure_login
), test_process(SkippingAndReorderingController
, "index").template
.assigns
["ran_filter"]
602 def test_conditional_skipping_of_filters
603 assert_nil
test_process(ConditionalSkippingController
, "login").template
.assigns
["ran_filter"]
604 assert_equal
%w( ensure_login find_user
), test_process(ConditionalSkippingController
, "change_password").template
.assigns
["ran_filter"]
606 assert_nil
test_process(ConditionalSkippingController
, "login").template
.controller
.instance_variable_get("@ran_after_filter")
607 assert_equal
%w( clean_up
), test_process(ConditionalSkippingController
, "change_password").template
.controller
.instance_variable_get("@ran_after_filter")
610 def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional
611 assert_equal
%w( conditional_in_parent conditional_in_parent
), test_process(ChildOfConditionalParentController
).template
.assigns
['ran_filter']
612 assert_nil
test_process(ChildOfConditionalParentController
, 'another_action').template
.assigns
['ran_filter']
615 def test_condition_skipping_of_filters_when_siblings_also_have_conditions
616 assert_equal
%w( conditional_in_parent conditional_in_parent
), test_process(ChildOfConditionalParentController
).template
.assigns
['ran_filter'], "1"
617 assert_equal
nil, test_process(AnotherChildOfConditionalParentController
).template
.assigns
['ran_filter']
618 assert_equal
%w( conditional_in_parent conditional_in_parent
), test_process(ChildOfConditionalParentController
).template
.assigns
['ran_filter']
621 def test_changing_the_requirements
622 assert_equal
nil, test_process(ChangingTheRequirementsController
, "go_wild").template
.assigns
['ran_filter']
625 def test_a_rescuing_around_filter
627 assert_nothing_raised
do
628 response
= test_process(RescuedController
)
631 assert response
.success
?
632 assert_equal("I rescued this: #<FilterTest::ErrorToRescue: Something made the bad noise.>", response
.body
)
636 def test_process(controller
, action
= "show")
637 request
= ActionController
::TestRequest.new
638 request
.action
= action
639 controller
.process(request
, ActionController
::TestResponse.new
)
645 class PostsController
< ActionController
::Base
646 def rescue_action(e
); raise e
; end
648 module AroundExceptions
649 class Error
< StandardError
; end
650 class Before
< Error
; end
651 class After
< Error
; end
653 include AroundExceptions
656 include AroundExceptions
659 module_eval
%w(raises_before raises_after raises_both no_raise no_filter
).map
{ |action
| "def #{action}; default_action end" }.join("\n")
663 render
:inline => "#{action_name} called"
667 class ControllerWithSymbolAsFilter
< PostsController
668 around_filter
:raise_before, :only => :raises_before
669 around_filter
:raise_after, :only => :raises_after
670 around_filter
:without_exception, :only => :no_raise
683 def without_exception
694 class ControllerWithFilterClass
< PostsController
695 class YieldingFilter
< DefaultFilter
696 def self.filter(controller
)
702 around_filter YieldingFilter
, :only => :raises_after
705 class ControllerWithFilterInstance
< PostsController
706 class YieldingFilter
< DefaultFilter
707 def filter(controller
)
713 around_filter YieldingFilter
.new
, :only => :raises_after
716 class ControllerWithFilterMethod
< PostsController
717 class YieldingFilter
< DefaultFilter
718 def filter(controller
)
724 around_filter YieldingFilter
.new
.method(:filter), :only => :raises_after
727 class ControllerWithProcFilter
< PostsController
728 around_filter(:only => :no_raise) do |c
,b
|
729 c
.instance_variable_set(:"@before", true)
731 c
.instance_variable_set(:"@after", true)
735 class ControllerWithNestedFilters
< ControllerWithSymbolAsFilter
736 around_filter
:raise_before, :raise_after, :without_exception, :only => :raises_both
739 class ControllerWithAllTypesOfFilters
< PostsController
740 before_filter
:before
741 around_filter
:around
743 around_filter
:around_again
748 @ran_filter << 'before'
752 @ran_filter << 'around (before yield)'
754 @ran_filter << 'around (after yield)'
758 @ran_filter << 'after'
762 @ran_filter << 'around_again (before yield)'
764 @ran_filter << 'around_again (after yield)'
768 class ControllerWithTwoLessFilters
< ControllerWithAllTypesOfFilters
769 skip_filter
:around_again
773 class YieldingAroundFiltersTest
< Test
::Unit::TestCase
774 include PostsController
::AroundExceptions
776 def test_filters_registering
777 assert_equal
1, ControllerWithFilterMethod
.filter_chain
.size
778 assert_equal
1, ControllerWithFilterClass
.filter_chain
.size
779 assert_equal
1, ControllerWithFilterInstance
.filter_chain
.size
780 assert_equal
3, ControllerWithSymbolAsFilter
.filter_chain
.size
781 assert_equal
6, ControllerWithNestedFilters
.filter_chain
.size
782 assert_equal
4, ControllerWithAllTypesOfFilters
.filter_chain
.size
786 controller
= PostsController
787 assert_nothing_raised
{ test_process(controller
,'no_raise') }
788 assert_nothing_raised
{ test_process(controller
,'raises_before') }
789 assert_nothing_raised
{ test_process(controller
,'raises_after') }
790 assert_nothing_raised
{ test_process(controller
,'no_filter') }
794 controller
= ControllerWithSymbolAsFilter
795 assert_nothing_raised
{ test_process(controller
,'no_raise') }
796 assert_raise(Before
) { test_process(controller
,'raises_before') }
797 assert_raise(After
) { test_process(controller
,'raises_after') }
798 assert_nothing_raised
{ test_process(controller
,'no_raise') }
802 controller
= ControllerWithFilterClass
803 assert_nothing_raised
{ test_process(controller
,'no_raise') }
804 assert_raise(After
) { test_process(controller
,'raises_after') }
807 def test_with_instance
808 controller
= ControllerWithFilterInstance
809 assert_nothing_raised
{ test_process(controller
,'no_raise') }
810 assert_raise(After
) { test_process(controller
,'raises_after') }
814 controller
= ControllerWithFilterMethod
815 assert_nothing_raised
{ test_process(controller
,'no_raise') }
816 assert_raise(After
) { test_process(controller
,'raises_after') }
820 controller
= test_process(ControllerWithProcFilter
,'no_raise')
821 assert controller
.template
.assigns
['before']
822 assert controller
.template
.assigns
['after']
825 def test_nested_filters
826 controller
= ControllerWithNestedFilters
827 assert_nothing_raised
do
829 test_process(controller
,'raises_both')
833 assert_raise Before
do
835 test_process(controller
,'raises_both')
841 def test_filter_order_with_all_filter_types
842 controller
= test_process(ControllerWithAllTypesOfFilters
,'no_raise')
843 assert_equal
'before around (before yield) around_again (before yield) around_again (after yield) around (after yield) after',controller
.template
.assigns
['ran_filter'].join(' ')
846 def test_filter_order_with_skip_filter_method
847 controller
= test_process(ControllerWithTwoLessFilters
,'no_raise')
848 assert_equal
'before around (before yield) around (after yield)',controller
.template
.assigns
['ran_filter'].join(' ')
851 def test_first_filter_in_multiple_before_filter_chain_halts
852 controller
= ::FilterTest::TestMultipleFiltersController.new
853 response
= test_process(controller
, 'fail_1')
854 assert_equal
' ', response
.body
855 assert_equal
1, controller
.instance_variable_get(:@try)
856 assert controller
.instance_variable_get(:@before_filter_chain_aborted)
859 def test_second_filter_in_multiple_before_filter_chain_halts
860 controller
= ::FilterTest::TestMultipleFiltersController.new
861 response
= test_process(controller
, 'fail_2')
862 assert_equal
' ', response
.body
863 assert_equal
2, controller
.instance_variable_get(:@try)
864 assert controller
.instance_variable_get(:@before_filter_chain_aborted)
867 def test_last_filter_in_multiple_before_filter_chain_halts
868 controller
= ::FilterTest::TestMultipleFiltersController.new
869 response
= test_process(controller
, 'fail_3')
870 assert_equal
' ', response
.body
871 assert_equal
3, controller
.instance_variable_get(:@try)
872 assert controller
.instance_variable_get(:@before_filter_chain_aborted)
876 def test_process(controller
, action
= "show")
877 request
= ActionController
::TestRequest.new
878 request
.action
= action
879 controller
.process(request
, ActionController
::TestResponse.new
)