filters_test.rb 29.6 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 512 513 514 515 516 517
  class ImplicitActionsController < ActionController::Base
    before_filter :find_user, :only => :edit

    private

    def find_user
      @user = 'Jenny'
    end
  end

518 519 520 521
  def test_sweeper_should_not_block_rendering
    response = test_process(SweeperTestController)
    assert_equal 'hello world', response.body
  end
N
Neeraj Singh 已提交
522 523

  def test_before_method_of_sweeper_should_always_return_true
524
    sweeper = ActionController::Caching::Sweeper.send(:new)
N
Neeraj Singh 已提交
525 526 527
    assert sweeper.before(TestController.new)
  end

528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
  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")
548
    assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters']
549 550 551 552 553 554
  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")
555
    assert_equal ["filter_one", "it didn't yield"], controller.assigns['filters']
556 557
  end

D
Initial  
David Heinemeier Hansson 已提交
558
  def test_added_filter_to_inheritance_graph
559
    assert_equal [ :ensure_login ], TestController.before_filters
D
Initial  
David Heinemeier Hansson 已提交
560 561 562
  end

  def test_base_class_in_isolation
563
    assert_equal [ ], ActionController::Base.before_filters
D
Initial  
David Heinemeier Hansson 已提交
564
  end
565

D
Initial  
David Heinemeier Hansson 已提交
566
  def test_prepending_filter
567
    assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_filters
D
Initial  
David Heinemeier Hansson 已提交
568
  end
569

D
Initial  
David Heinemeier Hansson 已提交
570
  def test_running_filters
571
    test_process(PrependingController)
572
    assert_equal %w( wonderful_life ensure_login ), assigns["ran_filter"]
D
Initial  
David Heinemeier Hansson 已提交
573 574 575
  end

  def test_running_filters_with_proc
576
    test_process(ProcController)
577
    assert assigns["ran_proc_filter"]
D
Initial  
David Heinemeier Hansson 已提交
578
  end
579

D
Initial  
David Heinemeier Hansson 已提交
580
  def test_running_filters_with_implicit_proc
581
    test_process(ImplicitProcController)
582
    assert assigns["ran_proc_filter"]
D
Initial  
David Heinemeier Hansson 已提交
583
  end
584

D
Initial  
David Heinemeier Hansson 已提交
585
  def test_running_filters_with_class
586
    test_process(AuditController)
587
    assert assigns["was_audited"]
D
Initial  
David Heinemeier Hansson 已提交
588
  end
589

590
  def test_running_anomolous_yet_valid_condition_filters
591
    test_process(AnomolousYetValidConditionController)
592 593 594 595
    assert_equal %w( ensure_login ), assigns["ran_filter"]
    assert assigns["ran_class_filter"]
    assert assigns["ran_proc_filter1"]
    assert assigns["ran_proc_filter2"]
596

597
    test_process(AnomolousYetValidConditionController, "show_without_filter")
598
    assert_nil assigns["ran_filter"]
599 600 601
    assert !assigns["ran_class_filter"]
    assert !assigns["ran_proc_filter1"]
    assert !assigns["ran_proc_filter2"]
602 603
  end

604
  def test_running_conditional_options
605
    test_process(ConditionalOptionsFilter)
606
    assert_equal %w( ensure_login ), assigns["ran_filter"]
607 608
  end

609
  def test_running_collection_condition_filters
610
    test_process(ConditionalCollectionFilterController)
611
    assert_equal %w( ensure_login ), assigns["ran_filter"]
612
    test_process(ConditionalCollectionFilterController, "show_without_filter")
613
    assert_nil assigns["ran_filter"]
614
    test_process(ConditionalCollectionFilterController, "another_action")
615
    assert_nil assigns["ran_filter"]
616 617 618
  end

  def test_running_only_condition_filters
619
    test_process(OnlyConditionSymController)
620
    assert_equal %w( ensure_login ), assigns["ran_filter"]
621
    test_process(OnlyConditionSymController, "show_without_filter")
622
    assert_nil assigns["ran_filter"]
623

624
    test_process(OnlyConditionProcController)
625
    assert assigns["ran_proc_filter"]
626
    test_process(OnlyConditionProcController, "show_without_filter")
627
    assert !assigns["ran_proc_filter"]
628

629
    test_process(OnlyConditionClassController)
630
    assert assigns["ran_class_filter"]
631
    test_process(OnlyConditionClassController, "show_without_filter")
632
    assert !assigns["ran_class_filter"]
633 634 635
  end

  def test_running_except_condition_filters
636
    test_process(ExceptConditionSymController)
637
    assert_equal %w( ensure_login ), assigns["ran_filter"]
638
    test_process(ExceptConditionSymController, "show_without_filter")
639
    assert_nil assigns["ran_filter"]
640

641
    test_process(ExceptConditionProcController)
642
    assert assigns["ran_proc_filter"]
643
    test_process(ExceptConditionProcController, "show_without_filter")
644
    assert !assigns["ran_proc_filter"]
645

646
    test_process(ExceptConditionClassController)
647
    assert assigns["ran_class_filter"]
648
    test_process(ExceptConditionClassController, "show_without_filter")
649
    assert !assigns["ran_class_filter"]
650 651 652
  end

  def test_running_before_and_after_condition_filters
653
    test_process(BeforeAndAfterConditionController)
654
    assert_equal %w( ensure_login clean_up_tmp), assigns["ran_filter"]
655
    test_process(BeforeAndAfterConditionController, "show_without_filter")
656
    assert_nil assigns["ran_filter"]
657
  end
658

D
Initial  
David Heinemeier Hansson 已提交
659
  def test_around_filter
660
    test_process(AroundFilterController)
661 662
    assert assigns["before_ran"]
    assert assigns["after_ran"]
D
Initial  
David Heinemeier Hansson 已提交
663
  end
664

665
  def test_before_after_class_filter
666
    test_process(BeforeAfterClassFilterController)
667 668
    assert assigns["before_ran"]
    assert assigns["after_ran"]
669 670
  end

D
Initial  
David Heinemeier Hansson 已提交
671
  def test_having_properties_in_around_filter
672
    test_process(AroundFilterController)
673
    assert_equal "before and after", assigns["execution_log"]
D
Initial  
David Heinemeier Hansson 已提交
674 675
  end

676
  def test_prepending_and_appending_around_filter
677
    test_process(MixedFilterController)
678 679 680
    assert_equal " before aroundfilter  before procfilter  before appended aroundfilter " +
                 " after appended aroundfilter  after procfilter  after aroundfilter ",
                 MixedFilterController.execution_log
D
Initial  
David Heinemeier Hansson 已提交
681
  end
682

683 684 685
  def test_rendering_breaks_filtering_chain
    response = test_process(RenderingController)
    assert_equal "something else", response.body
686
    assert !assigns["ran_action"]
687
  end
D
Initial  
David Heinemeier Hansson 已提交
688

689
  def test_before_filter_rendering_breaks_filtering_chain_for_after_filter
690
    test_process(RenderingController)
691 692 693 694 695
    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
696
    test_process(BeforeFilterRedirectionController)
697 698 699 700 701 702
    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
703
    test_process(RenderingForPrependAfterFilterController)
704 705 706 707 708
    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
709
    test_process(BeforeFilterRedirectionForPrependAfterFilterController)
710 711 712 713 714
    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

715 716 717 718 719 720 721 722 723 724 725 726
  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

727 728 729 730
  def test_dynamic_dispatch
    %w(foo bar baz).each do |action|
      request = ActionController::TestRequest.new
      request.query_parameters[:choose] = action
731
      response = DynamicDispatchController.action(action).call(request.env).last
732 733 734 735
      assert_equal action, response.body
    end
  end

736
  def test_running_prepended_before_and_after_filter
737
    test_process(PrependingBeforeAndAfterController)
738
    assert_equal %w( before_all between_before_all_and_after_all after_all ), assigns["ran_filter"]
739
  end
740

741
  def test_skipping_and_limiting_controller
742
    test_process(SkippingAndLimitedController, "index")
743
    assert_equal %w( ensure_login ), assigns["ran_filter"]
744
    test_process(SkippingAndLimitedController, "public")
745
    assert_nil assigns["ran_filter"]
746 747 748
  end

  def test_skipping_and_reordering_controller
749
    test_process(SkippingAndReorderingController, "index")
750
    assert_equal %w( find_record ensure_login ), assigns["ran_filter"]
751
  end
752

753
  def test_conditional_skipping_of_filters
754
    test_process(ConditionalSkippingController, "login")
755
    assert_nil assigns["ran_filter"]
756
    test_process(ConditionalSkippingController, "change_password")
757
    assert_equal %w( ensure_login find_user ), assigns["ran_filter"]
758

759
    test_process(ConditionalSkippingController, "login")
E
Emilio Tagua 已提交
760
    assert !@controller.instance_variable_defined?("@ran_after_filter")
761
    test_process(ConditionalSkippingController, "change_password")
762
    assert_equal %w( clean_up ), @controller.instance_variable_get("@ran_after_filter")
763 764
  end

765
  def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional
766
    test_process(ChildOfConditionalParentController)
767
    assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter']
768
    test_process(ChildOfConditionalParentController, 'another_action')
769
    assert_nil assigns['ran_filter']
770
  end
771

772
  def test_condition_skipping_of_filters_when_siblings_also_have_conditions
773
    test_process(ChildOfConditionalParentController)
774
    assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter']
775
    test_process(AnotherChildOfConditionalParentController)
776
    assert_equal %w( conditional_in_parent_after ), assigns['ran_filter']
777
    test_process(ChildOfConditionalParentController)
778
    assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter']
779 780
  end

781
  def test_changing_the_requirements
782
    test_process(ChangingTheRequirementsController, "go_wild")
783
    assert_nil assigns['ran_filter']
784
  end
785

786 787 788 789 790
  def test_a_rescuing_around_filter
    response = nil
    assert_nothing_raised do
      response = test_process(RescuedController)
    end
791

792 793 794
    assert response.success?
    assert_equal("I rescued this: #<FilterTest::ErrorToRescue: Something made the bad noise.>", response.body)
  end
795

796 797 798 799 800 801 802 803 804 805 806 807
  def test_filter_runs_for_implicitly_defined_action_when_needed
    test_process(ImplicitActionsController, 'edit')
    assert_equal 'Jenny', assigns(:user)
    assert_equal 'edit', response.body
  end

  def test_filter_does_not_run_for_implicity_defined_action_when_not_needed
    test_process(ImplicitActionsController, 'show')
    assert_nil assigns(:user)
    assert_equal 'show', response.body
  end

D
Initial  
David Heinemeier Hansson 已提交
808
  private
809
    def test_process(controller, action = "show")
810 811 812 813 814
      @controller = controller.is_a?(Class) ? controller.new : controller
      @request    = ActionController::TestRequest.new
      @response   = ActionController::TestResponse.new

      process(action)
D
Initial  
David Heinemeier Hansson 已提交
815
    end
816
end
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859



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 已提交
860
      wtf = 1 + 1
861 862 863 864

      yield

      # Do stuff...
A
Aaron Patterson 已提交
865
      wtf += 1
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
    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|
904
    c.instance_variable_set(:"@before", true)
905
    b.call
906
    c.instance_variable_set(:"@after", true)
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
  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
944
  $vbf = true
945
  skip_filter :around_again
946
  $vbf = false
947 948 949
  skip_filter :after
end

950
class YieldingAroundFiltersTest < ActionController::TestCase
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981
  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
982
    test_process(ControllerWithProcFilter,'no_raise')
983 984
    assert assigns['before']
    assert assigns['after']
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
  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

1003 1004 1005
  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(' ')
1006 1007 1008
  end

  def test_filter_order_with_skip_filter_method
1009
    test_process(ControllerWithTwoLessFilters,'no_raise')
1010
    assert_equal 'before around (before yield) around (after yield)', assigns['ran_filter'].join(' ')
1011 1012
  end

1013 1014 1015
  def test_first_filter_in_multiple_before_filter_chain_halts
    controller = ::FilterTest::TestMultipleFiltersController.new
    response = test_process(controller, 'fail_1')
1016
    assert_equal ' ', response.body
1017 1018 1019 1020 1021 1022
    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')
1023
    assert_equal ' ', response.body
1024 1025 1026 1027 1028 1029
    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')
1030
    assert_equal ' ', response.body
1031 1032 1033
    assert_equal 3, controller.instance_variable_get(:@try)
  end

1034 1035
  protected
    def test_process(controller, action = "show")
1036 1037
      @controller = controller.is_a?(Class) ? controller.new : controller
      process(action)
1038 1039
    end
end