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

3
# FIXME: crashes Ruby 1.9
D
Initial  
David Heinemeier Hansson 已提交
4 5 6
class FilterTest < Test::Unit::TestCase
  class TestController < ActionController::Base
    before_filter :ensure_login
7
    after_filter  :clean_up
D
Initial  
David Heinemeier Hansson 已提交
8 9

    def show
10
      render :inline => "ran action"
D
Initial  
David Heinemeier Hansson 已提交
11 12 13 14 15 16 17
    end

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

19 20 21 22
      def clean_up
        @ran_after_filter ||= []
        @ran_after_filter << "clean_up"
      end
D
Initial  
David Heinemeier Hansson 已提交
23
  end
24 25 26 27 28 29 30 31 32

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

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

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
  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
48 49 50
        if action_name == "fail_#{i}"
          head(404)
        end
51 52 53
      end
    end
  end
54 55 56 57 58 59

  class RenderingController < ActionController::Base
    before_filter :render_something_else

    def show
      @ran_action = true
60
      render :inline => "ran action"
61 62 63 64
    end

    private
      def render_something_else
65
        render :inline => "something else"
66 67
      end
  end
68

69 70
  class ConditionalFilterController < ActionController::Base
    def show
71
      render :inline => "ran action"
72 73 74
    end

    def another_action
75
      render :inline => "ran action"
76 77 78
    end

    def show_without_filter
79
      render :inline => "ran action without filter"
80 81 82 83 84 85 86 87 88 89 90 91
    end

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

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

93 94 95 96 97 98 99
      def rescue_action(e) raise(e) end
  end

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

100
  class OnlyConditionSymController < ConditionalFilterController
101 102 103 104 105 106 107 108 109
    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
110
    after_filter  :clean_up_tmp, :only => :show
111
  end
112 113

  class OnlyConditionProcController < ConditionalFilterController
114
    before_filter(:only => :show) {|c| c.instance_variable_set(:"@ran_proc_filter", true) }
115 116 117
  end

  class ExceptConditionProcController < ConditionalFilterController
118
    before_filter(:except => :show_without_filter) {|c| c.instance_variable_set(:"@ran_proc_filter", true) }
119 120 121
  end

  class ConditionalClassFilter
122
    def self.filter(controller) controller.instance_variable_set(:"@ran_class_filter", true) end
123 124 125 126 127 128 129 130 131 132 133
  end

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

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

  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)}
135 136
  end

137 138 139 140 141
  class ConditionalOptionsFilter < ConditionalFilterController
    before_filter :ensure_login, :if => Proc.new { |c| true }
    before_filter :clean_up_tmp, :if => Proc.new { |c| false }
  end

142 143 144 145 146 147 148 149
  class EmptyFilterChainController < TestController
    self.filter_chain.clear
    def show
      @action_executed = true
      render :text => "yawp!"
    end
  end

D
Initial  
David Heinemeier Hansson 已提交
150 151
  class PrependingController < TestController
    prepend_before_filter :wonderful_life
152
    # skip_before_filter :fire_flash
D
Initial  
David Heinemeier Hansson 已提交
153 154 155 156 157 158 159 160

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

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
  class SkippingAndLimitedController < TestController
    skip_before_filter :ensure_login
    before_filter :ensure_login, :only => :index

    def index
      render :text => 'ok'
    end
    
    def public
    end
  end
  
  class SkippingAndReorderingController < TestController
    skip_before_filter :ensure_login
    before_filter :find_record
    before_filter :ensure_login

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

185 186 187
  class ConditionalSkippingController < TestController
    skip_before_filter :ensure_login, :only => [ :login ]
    skip_after_filter  :clean_up,     :only => [ :login ]
188

189
    before_filter :find_user, :only => [ :change_password ]
190 191 192 193 194 195 196 197

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

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

199 200 201 202 203
    protected
      def find_user
        @ran_filter ||= []
        @ran_filter << "find_user"
      end
204
  end
205

206 207 208
  class ConditionalParentOfConditionalSkippingController < ConditionalFilterController
    before_filter :conditional_in_parent, :only => [:show, :another_action]
    after_filter  :conditional_in_parent, :only => [:show, :another_action]
209

210
    private
211

212 213 214 215 216
      def conditional_in_parent
        @ran_filter ||= []
        @ran_filter << 'conditional_in_parent'
      end
  end
217

218 219 220 221
  class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
    skip_before_filter :conditional_in_parent, :only => :another_action
    skip_after_filter  :conditional_in_parent, :only => :another_action
  end
222

223 224 225 226
  class AnotherChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
    skip_before_filter :conditional_in_parent, :only => :show
  end

D
Initial  
David Heinemeier Hansson 已提交
227
  class ProcController < PrependingController
228
    before_filter(proc { |c| c.instance_variable_set(:"@ran_proc_filter", true) })
D
Initial  
David Heinemeier Hansson 已提交
229 230 231
  end

  class ImplicitProcController < PrependingController
232
    before_filter { |c| c.instance_variable_set(:"@ran_proc_filter", true) }
D
Initial  
David Heinemeier Hansson 已提交
233 234 235 236
  end

  class AuditFilter
    def self.filter(controller)
237
      controller.instance_variable_set(:"@was_audited", true)
D
Initial  
David Heinemeier Hansson 已提交
238 239
    end
  end
240

D
Initial  
David Heinemeier Hansson 已提交
241 242 243 244
  class AroundFilter
    def before(controller)
      @execution_log = "before"
      controller.class.execution_log << " before aroundfilter " if controller.respond_to? :execution_log
245
      controller.instance_variable_set(:"@before_ran", true)
D
Initial  
David Heinemeier Hansson 已提交
246 247 248
    end

    def after(controller)
249 250
      controller.instance_variable_set(:"@execution_log", @execution_log + " and after")
      controller.instance_variable_set(:"@after_ran", true)
D
Initial  
David Heinemeier Hansson 已提交
251
      controller.class.execution_log << " after aroundfilter " if controller.respond_to? :execution_log
252
    end
D
Initial  
David Heinemeier Hansson 已提交
253 254 255 256 257 258 259 260 261
  end

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

    def after(controller)
      controller.class.execution_log << " after appended aroundfilter "
262 263 264
    end
  end

D
Initial  
David Heinemeier Hansson 已提交
265 266
  class AuditController < ActionController::Base
    before_filter(AuditFilter)
267

D
Initial  
David Heinemeier Hansson 已提交
268
    def show
269
      render :text => "hello"
D
Initial  
David Heinemeier Hansson 已提交
270 271 272 273 274 275 276
    end
  end

  class AroundFilterController < PrependingController
    around_filter AroundFilter.new
  end

277 278 279 280 281 282 283 284
  class BeforeAfterClassFilterController < PrependingController
    begin
      filter = AroundFilter.new
      before_filter filter
      after_filter filter
    end
  end

D
Initial  
David Heinemeier Hansson 已提交
285 286
  class MixedFilterController < PrependingController
    cattr_accessor :execution_log
287 288

    def initialize
D
Initial  
David Heinemeier Hansson 已提交
289 290 291 292 293 294 295 296 297
      @@execution_log = ""
    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
298

299 300 301 302 303 304 305
  class MixedSpecializationController < ActionController::Base
    class OutOfOrder < StandardError; end

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

    def foo
306
      render :text => 'foo'
307 308 309
    end

    def bar
310
      render :text => 'bar'
311 312 313 314 315 316 317 318 319 320 321 322
    end

    protected
      def first
        @first = true
      end

      def second
        raise OutOfOrder unless @first
      end
  end

323 324 325 326 327 328 329 330 331 332 333 334
  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 已提交
335

336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
  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
359

360
  class ErrorToRescue < Exception; end
361

362 363 364 365 366
  class RescuingAroundFilterWithBlock
    def filter(controller)
      begin
        yield
      rescue ErrorToRescue => ex
367
        controller.send! :render, :text => "I rescued this: #{ex.inspect}"
368 369 370
      end
    end
  end
371

372 373
  class RescuedController < ActionController::Base
    around_filter RescuingAroundFilterWithBlock.new
374

375 376 377
    def show
      raise ErrorToRescue.new("Something made the bad noise.")
    end
378

379 380 381 382 383
  private
    def rescue_action(exception)
      raise exception
    end
  end
384

385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
  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
        @filters  << "zomg it didn't yield"
        @filter_return_value
      end

      def filter_three
        @filters  << "filter_three"
      end

  end

  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")
    assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters']
  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")
    assert_equal ["filter_one", "zomg it didn't yield"], controller.assigns['filters']
  end

451 452 453 454 455
  def test_empty_filter_chain
    assert_equal 0, EmptyFilterChainController.filter_chain.size
    assert test_process(EmptyFilterChainController).template.assigns['action_executed']
  end

D
Initial  
David Heinemeier Hansson 已提交
456
  def test_added_filter_to_inheritance_graph
457
    assert_equal [ :ensure_login ], TestController.before_filters
D
Initial  
David Heinemeier Hansson 已提交
458 459 460
  end

  def test_base_class_in_isolation
461
    assert_equal [ ], ActionController::Base.before_filters
D
Initial  
David Heinemeier Hansson 已提交
462
  end
463

D
Initial  
David Heinemeier Hansson 已提交
464
  def test_prepending_filter
465
    assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_filters
D
Initial  
David Heinemeier Hansson 已提交
466
  end
467

D
Initial  
David Heinemeier Hansson 已提交
468 469 470 471 472 473 474
  def test_running_filters
    assert_equal %w( wonderful_life ensure_login ), test_process(PrependingController).template.assigns["ran_filter"]
  end

  def test_running_filters_with_proc
    assert test_process(ProcController).template.assigns["ran_proc_filter"]
  end
475

D
Initial  
David Heinemeier Hansson 已提交
476 477 478
  def test_running_filters_with_implicit_proc
    assert test_process(ImplicitProcController).template.assigns["ran_proc_filter"]
  end
479

D
Initial  
David Heinemeier Hansson 已提交
480 481 482
  def test_running_filters_with_class
    assert test_process(AuditController).template.assigns["was_audited"]
  end
483

484 485 486 487 488 489
  def test_running_anomolous_yet_valid_condition_filters
    response = test_process(AnomolousYetValidConditionController)
    assert_equal %w( ensure_login ), response.template.assigns["ran_filter"]
    assert response.template.assigns["ran_class_filter"]
    assert response.template.assigns["ran_proc_filter1"]
    assert response.template.assigns["ran_proc_filter2"]
490

491 492 493 494 495 496 497
    response = test_process(AnomolousYetValidConditionController, "show_without_filter")
    assert_equal nil, response.template.assigns["ran_filter"]
    assert !response.template.assigns["ran_class_filter"]
    assert !response.template.assigns["ran_proc_filter1"]
    assert !response.template.assigns["ran_proc_filter2"]
  end

498 499 500 501 502
  def test_running_conditional_options
    response = test_process(ConditionalOptionsFilter)
    assert_equal %w( ensure_login ), response.template.assigns["ran_filter"]
  end

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
  def test_running_collection_condition_filters
    assert_equal %w( ensure_login ), test_process(ConditionalCollectionFilterController).template.assigns["ran_filter"]
    assert_equal nil, test_process(ConditionalCollectionFilterController, "show_without_filter").template.assigns["ran_filter"]
    assert_equal nil, test_process(ConditionalCollectionFilterController, "another_action").template.assigns["ran_filter"]
  end

  def test_running_only_condition_filters
    assert_equal %w( ensure_login ), test_process(OnlyConditionSymController).template.assigns["ran_filter"]
    assert_equal nil, test_process(OnlyConditionSymController, "show_without_filter").template.assigns["ran_filter"]

    assert test_process(OnlyConditionProcController).template.assigns["ran_proc_filter"]
    assert !test_process(OnlyConditionProcController, "show_without_filter").template.assigns["ran_proc_filter"]

    assert test_process(OnlyConditionClassController).template.assigns["ran_class_filter"]
    assert !test_process(OnlyConditionClassController, "show_without_filter").template.assigns["ran_class_filter"]
  end

  def test_running_except_condition_filters
    assert_equal %w( ensure_login ), test_process(ExceptConditionSymController).template.assigns["ran_filter"]
    assert_equal nil, test_process(ExceptConditionSymController, "show_without_filter").template.assigns["ran_filter"]

    assert test_process(ExceptConditionProcController).template.assigns["ran_proc_filter"]
    assert !test_process(ExceptConditionProcController, "show_without_filter").template.assigns["ran_proc_filter"]

    assert test_process(ExceptConditionClassController).template.assigns["ran_class_filter"]
    assert !test_process(ExceptConditionClassController, "show_without_filter").template.assigns["ran_class_filter"]
  end

  def test_running_before_and_after_condition_filters
    assert_equal %w( ensure_login clean_up_tmp), test_process(BeforeAndAfterConditionController).template.assigns["ran_filter"]
    assert_equal nil, test_process(BeforeAndAfterConditionController, "show_without_filter").template.assigns["ran_filter"]
  end
535

D
Initial  
David Heinemeier Hansson 已提交
536 537 538 539 540
  def test_around_filter
    controller = test_process(AroundFilterController)
    assert controller.template.assigns["before_ran"]
    assert controller.template.assigns["after_ran"]
  end
541

542 543 544 545 546 547
  def test_before_after_class_filter
    controller = test_process(BeforeAfterClassFilterController)
    assert controller.template.assigns["before_ran"]
    assert controller.template.assigns["after_ran"]
  end

D
Initial  
David Heinemeier Hansson 已提交
548 549 550 551 552 553 554 555
  def test_having_properties_in_around_filter
    controller = test_process(AroundFilterController)
    assert_equal "before and after", controller.template.assigns["execution_log"]
  end

  def test_prepending_and_appending_around_filter
    controller = test_process(MixedFilterController)
    assert_equal " before aroundfilter  before procfilter  before appended aroundfilter " +
556
                 " after appended aroundfilter  after aroundfilter  after procfilter ",
D
Initial  
David Heinemeier Hansson 已提交
557 558
                 MixedFilterController.execution_log
  end
559

560 561 562 563 564
  def test_rendering_breaks_filtering_chain
    response = test_process(RenderingController)
    assert_equal "something else", response.body
    assert !response.template.assigns["ran_action"]
  end
D
Initial  
David Heinemeier Hansson 已提交
565

566 567 568 569 570 571 572 573 574 575 576 577
  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

578 579 580 581 582 583 584 585 586
  def test_dynamic_dispatch
    %w(foo bar baz).each do |action|
      request = ActionController::TestRequest.new
      request.query_parameters[:choose] = action
      response = DynamicDispatchController.process(request, ActionController::TestResponse.new)
      assert_equal action, response.body
    end
  end

587 588 589 590 591
  def test_running_prepended_before_and_after_filter
    assert_equal 3, PrependingBeforeAndAfterController.filter_chain.length
    response = test_process(PrependingBeforeAndAfterController)
    assert_equal %w( before_all between_before_all_and_after_all after_all ), response.template.assigns["ran_filter"]
  end
592 593 594 595 596 597 598 599 600
  
  def test_skipping_and_limiting_controller
    assert_equal %w( ensure_login ), test_process(SkippingAndLimitedController, "index").template.assigns["ran_filter"]
    assert_nil test_process(SkippingAndLimitedController, "public").template.assigns["ran_filter"]
  end

  def test_skipping_and_reordering_controller
    assert_equal %w( find_record ensure_login ), test_process(SkippingAndReorderingController, "index").template.assigns["ran_filter"]
  end
601

602 603
  def test_conditional_skipping_of_filters
    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"]
605 606 607 608 609

    assert_nil test_process(ConditionalSkippingController, "login").template.controller.instance_variable_get("@ran_after_filter")
    assert_equal %w( clean_up ), test_process(ConditionalSkippingController, "change_password").template.controller.instance_variable_get("@ran_after_filter")
  end

610 611 612 613
  def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional
    assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter']
    assert_nil test_process(ChildOfConditionalParentController, 'another_action').template.assigns['ran_filter']
  end
614

615 616 617 618 619 620
  def test_condition_skipping_of_filters_when_siblings_also_have_conditions
    assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter'], "1"
    assert_equal nil, test_process(AnotherChildOfConditionalParentController).template.assigns['ran_filter']
    assert_equal %w( conditional_in_parent conditional_in_parent ), test_process(ChildOfConditionalParentController).template.assigns['ran_filter']
  end

621 622 623
  def test_changing_the_requirements
    assert_equal nil, test_process(ChangingTheRequirementsController, "go_wild").template.assigns['ran_filter']
  end
624

625 626 627 628 629
  def test_a_rescuing_around_filter
    response = nil
    assert_nothing_raised do
      response = test_process(RescuedController)
    end
630

631 632 633
    assert response.success?
    assert_equal("I rescued this: #<FilterTest::ErrorToRescue: Something made the bad noise.>", response.body)
  end
634

D
Initial  
David Heinemeier Hansson 已提交
635
  private
636
    def test_process(controller, action = "show")
D
Initial  
David Heinemeier Hansson 已提交
637
      request = ActionController::TestRequest.new
638
      request.action = action
D
Initial  
David Heinemeier Hansson 已提交
639 640
      controller.process(request, ActionController::TestResponse.new)
    end
641
end
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 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 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728



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...
      1 + 1

      yield

      # Do stuff...
      1 + 1
    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|
729
    c.instance_variable_set(:"@before", true)
730
    b.call
731
    c.instance_variable_set(:"@after", true)
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 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 838 839 840 841 842 843 844 845 846 847 848 849 850
  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
  skip_filter :around_again
  skip_filter :after
end

class YieldingAroundFiltersTest < Test::Unit::TestCase
  include PostsController::AroundExceptions

  def test_filters_registering
    assert_equal 1, ControllerWithFilterMethod.filter_chain.size
    assert_equal 1, ControllerWithFilterClass.filter_chain.size
    assert_equal 1, ControllerWithFilterInstance.filter_chain.size
    assert_equal 3, ControllerWithSymbolAsFilter.filter_chain.size
    assert_equal 6, ControllerWithNestedFilters.filter_chain.size
    assert_equal 4, ControllerWithAllTypesOfFilters.filter_chain.size
  end

  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_method
    controller = ControllerWithFilterMethod
    assert_nothing_raised { test_process(controller,'no_raise') }
    assert_raise(After) { test_process(controller,'raises_after') }
  end

  def test_with_proc
    controller = test_process(ControllerWithProcFilter,'no_raise')
    assert controller.template.assigns['before']
    assert controller.template.assigns['after']
  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

  def test_filter_order_with_all_filter_types
    controller = test_process(ControllerWithAllTypesOfFilters,'no_raise')
    assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) around (after yield) after',controller.template.assigns['ran_filter'].join(' ')
  end

  def test_filter_order_with_skip_filter_method
    controller = test_process(ControllerWithTwoLessFilters,'no_raise')
    assert_equal 'before around (before yield) around (after yield)',controller.template.assigns['ran_filter'].join(' ')
  end

851 852 853
  def test_first_filter_in_multiple_before_filter_chain_halts
    controller = ::FilterTest::TestMultipleFiltersController.new
    response = test_process(controller, 'fail_1')
854
    assert_equal ' ', response.body
855 856 857 858 859 860 861
    assert_equal 1, controller.instance_variable_get(:@try)
    assert controller.instance_variable_get(:@before_filter_chain_aborted)
  end

  def test_second_filter_in_multiple_before_filter_chain_halts
    controller = ::FilterTest::TestMultipleFiltersController.new
    response = test_process(controller, 'fail_2')
862
    assert_equal ' ', response.body
863 864 865 866 867 868 869
    assert_equal 2, controller.instance_variable_get(:@try)
    assert controller.instance_variable_get(:@before_filter_chain_aborted)
  end

  def test_last_filter_in_multiple_before_filter_chain_halts
    controller = ::FilterTest::TestMultipleFiltersController.new
    response = test_process(controller, 'fail_3')
870
    assert_equal ' ', response.body
871 872 873 874
    assert_equal 3, controller.instance_variable_get(:@try)
    assert controller.instance_variable_get(:@before_filter_chain_aborted)
  end

875 876 877 878 879 880 881
  protected
    def test_process(controller, action = "show")
      request = ActionController::TestRequest.new
      request.action = action
      controller.process(request, ActionController::TestResponse.new)
    end
end