filters_test.rb 29.1 KB
Newer Older
1
require 'abstract_unit'
D
Initial  
David Heinemeier Hansson 已提交
2

3 4 5 6 7 8 9 10
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|
      define_method(pending) do |*args|
        $stderr.puts "#{pending} unimplemented: #{args.inspect}"
      end unless method_defined?(pending)
    end

11 12 13
    def before_filters
      filters = _process_action_callbacks.select { |c| c.kind == :before }
      filters.map! { |c| c.instance_variable_get(:@raw_filter) }
14 15 16
    end
  end

17 18 19 20 21
  def assigns(key = nil)
    assigns = {}
    instance_variable_names.each do |ivar|
      next if ActionController::Base.protected_instance_variables.include?(ivar)
      assigns[ivar[1..-1]] = instance_variable_get(ivar)
22
    end
23 24

    key.nil? ? assigns : assigns[key.to_s]
25 26 27
  end
end

28
class FilterTest < ActionController::TestCase
29

D
Initial  
David Heinemeier Hansson 已提交
30 31
  class TestController < ActionController::Base
    before_filter :ensure_login
32
    after_filter  :clean_up
D
Initial  
David Heinemeier Hansson 已提交
33 34

    def show
35
      render :inline => "ran action"
D
Initial  
David Heinemeier Hansson 已提交
36 37 38 39 40 41 42
    end

    private
      def ensure_login
        @ran_filter ||= []
        @ran_filter << "ensure_login"
      end
43

44 45 46 47
      def clean_up
        @ran_after_filter ||= []
        @ran_after_filter << "clean_up"
      end
D
Initial  
David Heinemeier Hansson 已提交
48
  end
49 50 51 52 53 54 55 56 57

  class ChangingTheRequirementsController < TestController
    before_filter :ensure_login, :except => [:go_wild]

    def go_wild
      render :text => "gobble"
    end
  end

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
  class TestMultipleFiltersController < ActionController::Base
    before_filter :try_1
    before_filter :try_2
    before_filter :try_3

    (1..3).each do |i|
      define_method "fail_#{i}" do
        render :text => i.to_s
      end
    end

    protected
    (1..3).each do |i|
      define_method "try_#{i}" do
        instance_variable_set :@try, i
73 74 75
        if action_name == "fail_#{i}"
          head(404)
        end
76 77 78
      end
    end
  end
79 80

  class RenderingController < ActionController::Base
81 82
    before_filter :before_filter_rendering
    after_filter :unreached_after_filter
83 84 85

    def show
      @ran_action = true
86
      render :inline => "ran action"
87 88 89
    end

    private
90 91 92
      def before_filter_rendering
        @ran_filter ||= []
        @ran_filter << "before_filter_rendering"
93
        render :inline => "something else"
94
      end
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142

      def unreached_after_filter
        @ran_filter << "unreached_after_filter_after_render"
      end
  end

  class RenderingForPrependAfterFilterController < RenderingController
    prepend_after_filter :unreached_prepend_after_filter

    private
      def unreached_prepend_after_filter
        @ran_filter << "unreached_preprend_after_filter_after_render"
      end
  end

  class BeforeFilterRedirectionController < ActionController::Base
    before_filter :before_filter_redirects
    after_filter :unreached_after_filter

    def show
      @ran_action = true
      render :inline => "ran show action"
    end

    def target_of_redirection
      @ran_target_of_redirection = true
      render :inline => "ran target_of_redirection action"
    end

    private
      def before_filter_redirects
        @ran_filter ||= []
        @ran_filter << "before_filter_redirects"
        redirect_to(:action => 'target_of_redirection')
      end

      def unreached_after_filter
        @ran_filter << "unreached_after_filter_after_redirection"
      end
  end

  class BeforeFilterRedirectionForPrependAfterFilterController < BeforeFilterRedirectionController
    prepend_after_filter :unreached_prepend_after_filter_after_redirection

    private
      def unreached_prepend_after_filter_after_redirection
        @ran_filter << "unreached_prepend_after_filter_after_redirection"
      end
143
  end
144

145 146
  class ConditionalFilterController < ActionController::Base
    def show
147
      render :inline => "ran action"
148 149 150
    end

    def another_action
151
      render :inline => "ran action"
152 153 154
    end

    def show_without_filter
155
      render :inline => "ran action without filter"
156 157 158 159 160 161 162 163 164 165 166 167
    end

    private
      def ensure_login
        @ran_filter ||= []
        @ran_filter << "ensure_login"
      end

      def clean_up_tmp
        @ran_filter ||= []
        @ran_filter << "clean_up_tmp"
      end
168

169 170 171 172 173 174 175
      def rescue_action(e) raise(e) end
  end

  class ConditionalCollectionFilterController < ConditionalFilterController
    before_filter :ensure_login, :except => [ :show_without_filter, :another_action ]
  end

176
  class OnlyConditionSymController < ConditionalFilterController
177 178 179 180 181 182 183 184 185
    before_filter :ensure_login, :only => :show
  end

  class ExceptConditionSymController < ConditionalFilterController
    before_filter :ensure_login, :except => :show_without_filter
  end

  class BeforeAndAfterConditionController < ConditionalFilterController
    before_filter :ensure_login, :only => :show
186
    after_filter  :clean_up_tmp, :only => :show
187
  end
188 189

  class OnlyConditionProcController < ConditionalFilterController
190
    before_filter(:only => :show) {|c| c.instance_variable_set(:"@ran_proc_filter", true) }
191 192 193
  end

  class ExceptConditionProcController < ConditionalFilterController
194
    before_filter(:except => :show_without_filter) {|c| c.instance_variable_set(:"@ran_proc_filter", true) }
195 196 197
  end

  class ConditionalClassFilter
198
    def self.filter(controller) controller.instance_variable_set(:"@ran_class_filter", true) end
199 200 201 202 203 204 205 206 207 208 209
  end

  class OnlyConditionClassController < ConditionalFilterController
    before_filter ConditionalClassFilter, :only => :show
  end

  class ExceptConditionClassController < ConditionalFilterController
    before_filter ConditionalClassFilter, :except => :show_without_filter
  end

  class AnomolousYetValidConditionController < ConditionalFilterController
210
    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)}
211 212
  end

213 214 215 216 217
  class ConditionalOptionsFilter < ConditionalFilterController
    before_filter :ensure_login, :if => Proc.new { |c| true }
    before_filter :clean_up_tmp, :if => Proc.new { |c| false }
  end

D
Initial  
David Heinemeier Hansson 已提交
218 219
  class PrependingController < TestController
    prepend_before_filter :wonderful_life
220
    # skip_before_filter :fire_flash
D
Initial  
David Heinemeier Hansson 已提交
221 222 223 224 225 226 227 228

    private
      def wonderful_life
        @ran_filter ||= []
        @ran_filter << "wonderful_life"
      end
  end

229 230 231 232 233 234 235
  class SkippingAndLimitedController < TestController
    skip_before_filter :ensure_login
    before_filter :ensure_login, :only => :index

    def index
      render :text => 'ok'
    end
236

237
    def public
238
      render :text => 'ok'
239 240
    end
  end
241

242 243 244 245 246
  class SkippingAndReorderingController < TestController
    skip_before_filter :ensure_login
    before_filter :find_record
    before_filter :ensure_login

247 248 249 250
    def index
      render :text => 'ok'
    end

251 252 253 254 255 256 257
    private
      def find_record
        @ran_filter ||= []
        @ran_filter << "find_record"
      end
  end

258 259 260
  class ConditionalSkippingController < TestController
    skip_before_filter :ensure_login, :only => [ :login ]
    skip_after_filter  :clean_up,     :only => [ :login ]
261

262
    before_filter :find_user, :only => [ :change_password ]
263 264 265 266 267 268 269 270

    def login
      render :inline => "ran action"
    end

    def change_password
      render :inline => "ran action"
    end
271

272 273 274 275 276
    protected
      def find_user
        @ran_filter ||= []
        @ran_filter << "find_user"
      end
277
  end
278

279
  class ConditionalParentOfConditionalSkippingController < ConditionalFilterController
280 281
    before_filter :conditional_in_parent_before, :only => [:show, :another_action]
    after_filter  :conditional_in_parent_after, :only => [:show, :another_action]
282

283
    private
284

285
      def conditional_in_parent_before
286
        @ran_filter ||= []
287 288 289 290 291 292
        @ran_filter << 'conditional_in_parent_before'
      end

      def conditional_in_parent_after
        @ran_filter ||= []
        @ran_filter << 'conditional_in_parent_after'
293 294
      end
  end
295

296
  class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
297 298
    skip_before_filter :conditional_in_parent_before, :only => :another_action
    skip_after_filter  :conditional_in_parent_after, :only => :another_action
299
  end
300

301
  class AnotherChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
302
    skip_before_filter :conditional_in_parent_before, :only => :show
303 304
  end

D
Initial  
David Heinemeier Hansson 已提交
305
  class ProcController < PrependingController
306
    before_filter(proc { |c| c.instance_variable_set(:"@ran_proc_filter", true) })
D
Initial  
David Heinemeier Hansson 已提交
307 308 309
  end

  class ImplicitProcController < PrependingController
310
    before_filter { |c| c.instance_variable_set(:"@ran_proc_filter", true) }
D
Initial  
David Heinemeier Hansson 已提交
311 312 313 314
  end

  class AuditFilter
    def self.filter(controller)
315
      controller.instance_variable_set(:"@was_audited", true)
D
Initial  
David Heinemeier Hansson 已提交
316 317
    end
  end
318

D
Initial  
David Heinemeier Hansson 已提交
319 320 321 322
  class AroundFilter
    def before(controller)
      @execution_log = "before"
      controller.class.execution_log << " before aroundfilter " if controller.respond_to? :execution_log
323
      controller.instance_variable_set(:"@before_ran", true)
D
Initial  
David Heinemeier Hansson 已提交
324 325 326
    end

    def after(controller)
327 328
      controller.instance_variable_set(:"@execution_log", @execution_log + " and after")
      controller.instance_variable_set(:"@after_ran", true)
D
Initial  
David Heinemeier Hansson 已提交
329
      controller.class.execution_log << " after aroundfilter " if controller.respond_to? :execution_log
330
    end
D
Initial  
David Heinemeier Hansson 已提交
331 332 333 334 335 336 337 338 339
  end

  class AppendedAroundFilter
    def before(controller)
      controller.class.execution_log << " before appended aroundfilter "
    end

    def after(controller)
      controller.class.execution_log << " after appended aroundfilter "
340 341 342
    end
  end

D
Initial  
David Heinemeier Hansson 已提交
343 344
  class AuditController < ActionController::Base
    before_filter(AuditFilter)
345

D
Initial  
David Heinemeier Hansson 已提交
346
    def show
347
      render :text => "hello"
D
Initial  
David Heinemeier Hansson 已提交
348 349 350 351 352 353 354
    end
  end

  class AroundFilterController < PrependingController
    around_filter AroundFilter.new
  end

355 356 357 358 359 360 361 362
  class BeforeAfterClassFilterController < PrependingController
    begin
      filter = AroundFilter.new
      before_filter filter
      after_filter filter
    end
  end

D
Initial  
David Heinemeier Hansson 已提交
363 364
  class MixedFilterController < PrependingController
    cattr_accessor :execution_log
365 366

    def initialize
D
Initial  
David Heinemeier Hansson 已提交
367
      @@execution_log = ""
368
      super()
D
Initial  
David Heinemeier Hansson 已提交
369 370 371 372 373 374 375 376
    end

    before_filter { |c| c.class.execution_log << " before procfilter "  }
    prepend_around_filter AroundFilter.new

    after_filter  { |c| c.class.execution_log << " after procfilter " }
    append_around_filter AppendedAroundFilter.new
  end
377

378 379 380 381 382 383 384
  class MixedSpecializationController < ActionController::Base
    class OutOfOrder < StandardError; end

    before_filter :first
    before_filter :second, :only => :foo

    def foo
385
      render :text => 'foo'
386 387 388
    end

    def bar
389
      render :text => 'bar'
390 391 392 393 394 395 396 397 398 399 400 401
    end

    protected
      def first
        @first = true
      end

      def second
        raise OutOfOrder unless @first
      end
  end

402 403 404 405 406 407 408 409 410 411 412 413
  class DynamicDispatchController < ActionController::Base
    before_filter :choose

    %w(foo bar baz).each do |action|
      define_method(action) { render :text => action }
    end

    private
      def choose
        self.action_name = params[:choose]
      end
  end
D
Initial  
David Heinemeier Hansson 已提交
414

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
  class PrependingBeforeAndAfterController < ActionController::Base
    prepend_before_filter :before_all
    prepend_after_filter :after_all
    before_filter :between_before_all_and_after_all

    def before_all
      @ran_filter ||= []
      @ran_filter << 'before_all'
    end

    def after_all
      @ran_filter ||= []
      @ran_filter << 'after_all'
    end

    def between_before_all_and_after_all
      @ran_filter ||= []
      @ran_filter << 'between_before_all_and_after_all'
    end
    def show
      render :text => 'hello'
    end
  end
438

439
  class ErrorToRescue < Exception; end
440

441 442 443 444 445
  class RescuingAroundFilterWithBlock
    def filter(controller)
      begin
        yield
      rescue ErrorToRescue => ex
446
        controller.__send__ :render, :text => "I rescued this: #{ex.inspect}"
447 448 449
      end
    end
  end
450

451 452
  class RescuedController < ActionController::Base
    around_filter RescuingAroundFilterWithBlock.new
453

454 455 456
    def show
      raise ErrorToRescue.new("Something made the bad noise.")
    end
457

458 459 460 461 462
  private
    def rescue_action(exception)
      raise exception
    end
  end
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
  class NonYieldingAroundFilterController < ActionController::Base

    before_filter :filter_one
    around_filter :non_yielding_filter
    before_filter :filter_two
    after_filter :filter_three

    def index
      render :inline => "index"
    end

    #make sure the controller complains
    def rescue_action(e); raise e; end

    private

      def filter_one
        @filters  ||= []
        @filters  << "filter_one"
      end

      def filter_two
        @filters  << "filter_two"
      end

      def non_yielding_filter
490
        @filters  << "it didn't yield"
491 492 493 494 495 496 497 498 499
        @filter_return_value
      end

      def filter_three
        @filters  << "filter_three"
      end

  end

500 501
  class ::AppSweeper < ActionController::Caching::Sweeper; end
  class SweeperTestController < ActionController::Base
502
    cache_sweeper :app_sweeper
503 504 505 506
    def show
      render :text => 'hello world'
    end
  end
507

508 509 510 511
  def test_sweeper_should_not_block_rendering
    response = test_process(SweeperTestController)
    assert_equal 'hello world', response.body
  end
N
Neeraj Singh 已提交
512 513

  def test_before_method_of_sweeper_should_always_return_true
514
    sweeper = ActionController::Caching::Sweeper.send(:new)
N
Neeraj Singh 已提交
515 516 517
    assert sweeper.before(TestController.new)
  end

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
  def test_non_yielding_around_filters_not_returning_false_do_not_raise
    controller = NonYieldingAroundFilterController.new
    controller.instance_variable_set "@filter_return_value", true
    assert_nothing_raised do
      test_process(controller, "index")
    end
  end

  def test_non_yielding_around_filters_returning_false_do_not_raise
    controller = NonYieldingAroundFilterController.new
    controller.instance_variable_set "@filter_return_value", false
    assert_nothing_raised do
      test_process(controller, "index")
    end
  end

  def test_after_filters_are_not_run_if_around_filter_returns_false
    controller = NonYieldingAroundFilterController.new
    controller.instance_variable_set "@filter_return_value", false
    test_process(controller, "index")
538
    assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters']
539 540 541 542 543 544
  end

  def test_after_filters_are_not_run_if_around_filter_does_not_yield
    controller = NonYieldingAroundFilterController.new
    controller.instance_variable_set "@filter_return_value", true
    test_process(controller, "index")
545
    assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters']
546 547
  end

D
Initial  
David Heinemeier Hansson 已提交
548
  def test_added_filter_to_inheritance_graph
549
    assert_equal [ :ensure_login ], TestController.before_filters
D
Initial  
David Heinemeier Hansson 已提交
550 551 552
  end

  def test_base_class_in_isolation
553
    assert_equal [ ], ActionController::Base.before_filters
D
Initial  
David Heinemeier Hansson 已提交
554
  end
555

D
Initial  
David Heinemeier Hansson 已提交
556
  def test_prepending_filter
557
    assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_filters
D
Initial  
David Heinemeier Hansson 已提交
558
  end
559

D
Initial  
David Heinemeier Hansson 已提交
560
  def test_running_filters
561
    test_process(PrependingController)
562
    assert_equal %w( wonderful_life ensure_login ), assigns["ran_filter"]
D
Initial  
David Heinemeier Hansson 已提交
563 564 565
  end

  def test_running_filters_with_proc
566
    test_process(ProcController)
567
    assert assigns["ran_proc_filter"]
D
Initial  
David Heinemeier Hansson 已提交
568
  end
569

D
Initial  
David Heinemeier Hansson 已提交
570
  def test_running_filters_with_implicit_proc
571
    test_process(ImplicitProcController)
572
    assert assigns["ran_proc_filter"]
D
Initial  
David Heinemeier Hansson 已提交
573
  end
574

D
Initial  
David Heinemeier Hansson 已提交
575
  def test_running_filters_with_class
576
    test_process(AuditController)
577
    assert assigns["was_audited"]
D
Initial  
David Heinemeier Hansson 已提交
578
  end
579

580
  def test_running_anomolous_yet_valid_condition_filters
581
    test_process(AnomolousYetValidConditionController)
582 583 584 585
    assert_equal %w( ensure_login ), assigns["ran_filter"]
    assert assigns["ran_class_filter"]
    assert assigns["ran_proc_filter1"]
    assert assigns["ran_proc_filter2"]
586

587
    test_process(AnomolousYetValidConditionController, "show_without_filter")
588
    assert_nil assigns["ran_filter"]
589 590 591
    assert !assigns["ran_class_filter"]
    assert !assigns["ran_proc_filter1"]
    assert !assigns["ran_proc_filter2"]
592 593
  end

594
  def test_running_conditional_options
595
    test_process(ConditionalOptionsFilter)
596
    assert_equal %w( ensure_login ), assigns["ran_filter"]
597 598
  end

599
  def test_running_collection_condition_filters
600
    test_process(ConditionalCollectionFilterController)
601
    assert_equal %w( ensure_login ), assigns["ran_filter"]
602
    test_process(ConditionalCollectionFilterController, "show_without_filter")
603
    assert_nil assigns["ran_filter"]
604
    test_process(ConditionalCollectionFilterController, "another_action")
605
    assert_nil assigns["ran_filter"]
606 607 608
  end

  def test_running_only_condition_filters
609
    test_process(OnlyConditionSymController)
610
    assert_equal %w( ensure_login ), assigns["ran_filter"]
611
    test_process(OnlyConditionSymController, "show_without_filter")
612
    assert_nil assigns["ran_filter"]
613

614
    test_process(OnlyConditionProcController)
615
    assert assigns["ran_proc_filter"]
616
    test_process(OnlyConditionProcController, "show_without_filter")
617
    assert !assigns["ran_proc_filter"]
618

619
    test_process(OnlyConditionClassController)
620
    assert assigns["ran_class_filter"]
621
    test_process(OnlyConditionClassController, "show_without_filter")
622
    assert !assigns["ran_class_filter"]
623 624 625
  end

  def test_running_except_condition_filters
626
    test_process(ExceptConditionSymController)
627
    assert_equal %w( ensure_login ), assigns["ran_filter"]
628
    test_process(ExceptConditionSymController, "show_without_filter")
629
    assert_nil assigns["ran_filter"]
630

631
    test_process(ExceptConditionProcController)
632
    assert assigns["ran_proc_filter"]
633
    test_process(ExceptConditionProcController, "show_without_filter")
634
    assert !assigns["ran_proc_filter"]
635

636
    test_process(ExceptConditionClassController)
637
    assert assigns["ran_class_filter"]
638
    test_process(ExceptConditionClassController, "show_without_filter")
639
    assert !assigns["ran_class_filter"]
640 641 642
  end

  def test_running_before_and_after_condition_filters
643
    test_process(BeforeAndAfterConditionController)
644
    assert_equal %w( ensure_login clean_up_tmp), assigns["ran_filter"]
645
    test_process(BeforeAndAfterConditionController, "show_without_filter")
646
    assert_nil assigns["ran_filter"]
647
  end
648

D
Initial  
David Heinemeier Hansson 已提交
649
  def test_around_filter
650
    test_process(AroundFilterController)
651 652
    assert assigns["before_ran"]
    assert assigns["after_ran"]
D
Initial  
David Heinemeier Hansson 已提交
653
  end
654

655
  def test_before_after_class_filter
656
    test_process(BeforeAfterClassFilterController)
657 658
    assert assigns["before_ran"]
    assert assigns["after_ran"]
659 660
  end

D
Initial  
David Heinemeier Hansson 已提交
661
  def test_having_properties_in_around_filter
662
    test_process(AroundFilterController)
663
    assert_equal "before and after", assigns["execution_log"]
D
Initial  
David Heinemeier Hansson 已提交
664 665
  end

666 667 668 669 670
  def test_prepending_and_appending_around_filter
    controller = test_process(MixedFilterController)
    assert_equal " before aroundfilter  before procfilter  before appended aroundfilter " +
                 " after appended aroundfilter  after procfilter  after aroundfilter ",
                 MixedFilterController.execution_log
D
Initial  
David Heinemeier Hansson 已提交
671
  end
672

673 674 675
  def test_rendering_breaks_filtering_chain
    response = test_process(RenderingController)
    assert_equal "something else", response.body
676
    assert !assigns["ran_action"]
677
  end
D
Initial  
David Heinemeier Hansson 已提交
678

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
  def test_before_filter_rendering_breaks_filtering_chain_for_after_filter
    response = test_process(RenderingController)
    assert_equal %w( before_filter_rendering ), assigns["ran_filter"]
    assert !assigns["ran_action"]
  end

  def test_before_filter_redirects_breaks_filtering_chain_for_after_filter
    response = test_process(BeforeFilterRedirectionController)
    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"]
  end

  def test_before_filter_rendering_breaks_filtering_chain_for_preprend_after_filter
    response = test_process(RenderingForPrependAfterFilterController)
    assert_equal %w( before_filter_rendering ), assigns["ran_filter"]
    assert !assigns["ran_action"]
  end

  def test_before_filter_redirects_breaks_filtering_chain_for_preprend_after_filter
    response = test_process(BeforeFilterRedirectionForPrependAfterFilterController)
    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"]
  end

705 706 707 708 709 710 711 712 713 714 715 716
  def test_filters_with_mixed_specialization_run_in_order
    assert_nothing_raised do
      response = test_process(MixedSpecializationController, 'bar')
      assert_equal 'bar', response.body
    end

    assert_nothing_raised do
      response = test_process(MixedSpecializationController, 'foo')
      assert_equal 'foo', response.body
    end
  end

717 718 719 720
  def test_dynamic_dispatch
    %w(foo bar baz).each do |action|
      request = ActionController::TestRequest.new
      request.query_parameters[:choose] = action
721
      response = DynamicDispatchController.action(action).call(request.env).last
722 723 724 725
      assert_equal action, response.body
    end
  end

726
  def test_running_prepended_before_and_after_filter
727
    test_process(PrependingBeforeAndAfterController)
728
    assert_equal %w( before_all between_before_all_and_after_all after_all ), assigns["ran_filter"]
729
  end
730

731
  def test_skipping_and_limiting_controller
732
    test_process(SkippingAndLimitedController, "index")
733
    assert_equal %w( ensure_login ), assigns["ran_filter"]
734
    test_process(SkippingAndLimitedController, "public")
735
    assert_nil assigns["ran_filter"]
736 737 738
  end

  def test_skipping_and_reordering_controller
739
    test_process(SkippingAndReorderingController, "index")
740
    assert_equal %w( find_record ensure_login ), assigns["ran_filter"]
741
  end
742

743
  def test_conditional_skipping_of_filters
744
    test_process(ConditionalSkippingController, "login")
745
    assert_nil assigns["ran_filter"]
746
    test_process(ConditionalSkippingController, "change_password")
747
    assert_equal %w( ensure_login find_user ), assigns["ran_filter"]
748

749
    test_process(ConditionalSkippingController, "login")
E
Emilio Tagua 已提交
750
    assert !@controller.instance_variable_defined?("@ran_after_filter")
751
    test_process(ConditionalSkippingController, "change_password")
752
    assert_equal %w( clean_up ), @controller.instance_variable_get("@ran_after_filter")
753 754
  end

755
  def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional
756
    test_process(ChildOfConditionalParentController)
757
    assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter']
758
    test_process(ChildOfConditionalParentController, 'another_action')
759
    assert_nil assigns['ran_filter']
760
  end
761

762
  def test_condition_skipping_of_filters_when_siblings_also_have_conditions
763
    test_process(ChildOfConditionalParentController)
764
    assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter']
765
    test_process(AnotherChildOfConditionalParentController)
766
    assert_equal %w( conditional_in_parent_after ), assigns['ran_filter']
767
    test_process(ChildOfConditionalParentController)
768
    assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter']
769 770
  end

771
  def test_changing_the_requirements
772
    test_process(ChangingTheRequirementsController, "go_wild")
773
    assert_nil assigns['ran_filter']
774
  end
775

776 777 778 779 780
  def test_a_rescuing_around_filter
    response = nil
    assert_nothing_raised do
      response = test_process(RescuedController)
    end
781

782 783 784
    assert response.success?
    assert_equal("I rescued this: #<FilterTest::ErrorToRescue: Something made the bad noise.>", response.body)
  end
785

D
Initial  
David Heinemeier Hansson 已提交
786
  private
787
    def test_process(controller, action = "show")
788 789 790 791 792
      @controller = controller.is_a?(Class) ? controller.new : controller
      @request    = ActionController::TestRequest.new
      @response   = ActionController::TestResponse.new

      process(action)
D
Initial  
David Heinemeier Hansson 已提交
793
    end
794
end
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837



class PostsController < ActionController::Base
  def rescue_action(e); raise e; end

  module AroundExceptions
    class Error < StandardError ; end
    class Before < Error ; end
    class After < Error ; end
  end
  include AroundExceptions

  class DefaultFilter
    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")

  private
    def default_action
      render :inline => "#{action_name} called"
    end
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

  private
    def raise_before
      raise Before
      yield
    end

    def raise_after
      yield
      raise After
    end

    def without_exception
      # Do stuff...
A
Aaron Patterson 已提交
838
      wtf = 1 + 1
839 840 841 842

      yield

      # Do stuff...
A
Aaron Patterson 已提交
843
      wtf += 1
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
    end
end

class ControllerWithFilterClass < PostsController
  class YieldingFilter < DefaultFilter
    def self.filter(controller)
      yield
      raise After
    end
  end

  around_filter YieldingFilter, :only => :raises_after
end

class ControllerWithFilterInstance < PostsController
  class YieldingFilter < DefaultFilter
    def filter(controller)
      yield
      raise After
    end
  end

  around_filter YieldingFilter.new, :only => :raises_after
end

class ControllerWithFilterMethod < PostsController
  class YieldingFilter < DefaultFilter
    def filter(controller)
      yield
      raise After
    end
  end

  around_filter YieldingFilter.new.method(:filter), :only => :raises_after
end

class ControllerWithProcFilter < PostsController
  around_filter(:only => :no_raise) do |c,b|
882
    c.instance_variable_set(:"@before", true)
883
    b.call
884
    c.instance_variable_set(:"@after", true)
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
  end
end

class ControllerWithNestedFilters < ControllerWithSymbolAsFilter
  around_filter :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

  private
  def before
    @ran_filter ||= []
    @ran_filter << 'before'
  end

  def around
    @ran_filter << 'around (before yield)'
    yield
    @ran_filter << 'around (after yield)'
  end

  def after
    @ran_filter << 'after'
  end

  def around_again
    @ran_filter << 'around_again (before yield)'
    yield
    @ran_filter << 'around_again (after yield)'
  end
end

class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters
922
  $vbf = true
923
  skip_filter :around_again
924
  $vbf = false
925 926 927
  skip_filter :after
end

928
class YieldingAroundFiltersTest < ActionController::TestCase
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
  include PostsController::AroundExceptions

  def test_base
    controller = PostsController
    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') }
  end

  def test_with_symbol
    controller = ControllerWithSymbolAsFilter
    assert_nothing_raised { test_process(controller,'no_raise') }
    assert_raise(Before) { test_process(controller,'raises_before') }
    assert_raise(After) { test_process(controller,'raises_after') }
    assert_nothing_raised { test_process(controller,'no_raise') }
  end

  def test_with_class
    controller = ControllerWithFilterClass
    assert_nothing_raised { test_process(controller,'no_raise') }
    assert_raise(After) { test_process(controller,'raises_after') }
  end

  def test_with_instance
    controller = ControllerWithFilterInstance
    assert_nothing_raised { test_process(controller,'no_raise') }
    assert_raise(After) { test_process(controller,'raises_after') }
  end

  def test_with_proc
960
    test_process(ControllerWithProcFilter,'no_raise')
961 962
    assert assigns['before']
    assert assigns['after']
963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
  end

  def test_nested_filters
    controller = ControllerWithNestedFilters
    assert_nothing_raised do
      begin
        test_process(controller,'raises_both')
      rescue Before, After
      end
    end
    assert_raise Before do
      begin
        test_process(controller,'raises_both')
      rescue After
      end
    end
  end

981 982 983
  def test_filter_order_with_all_filter_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(' ')
984 985 986
  end

  def test_filter_order_with_skip_filter_method
987
    test_process(ControllerWithTwoLessFilters,'no_raise')
988
    assert_equal 'before around (before yield) around (after yield)', assigns['ran_filter'].join(' ')
989 990
  end

991 992 993
  def test_first_filter_in_multiple_before_filter_chain_halts
    controller = ::FilterTest::TestMultipleFiltersController.new
    response = test_process(controller, 'fail_1')
994
    assert_equal ' ', response.body
995 996 997 998 999 1000
    assert_equal 1, controller.instance_variable_get(:@try)
  end

  def test_second_filter_in_multiple_before_filter_chain_halts
    controller = ::FilterTest::TestMultipleFiltersController.new
    response = test_process(controller, 'fail_2')
1001
    assert_equal ' ', response.body
1002 1003 1004 1005 1006 1007
    assert_equal 2, controller.instance_variable_get(:@try)
  end

  def test_last_filter_in_multiple_before_filter_chain_halts
    controller = ::FilterTest::TestMultipleFiltersController.new
    response = test_process(controller, 'fail_3')
1008
    assert_equal ' ', response.body
1009 1010 1011
    assert_equal 3, controller.instance_variable_get(:@try)
  end

1012 1013
  protected
    def test_process(controller, action = "show")
1014 1015
      @controller = controller.is_a?(Class) ? controller.new : controller
      process(action)
1016 1017
    end
end