aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/testing/setup_and_teardown.rb
blob: 1639462fae5d11685675d63dd6bfb022e27b8e52 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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
module ActiveSupport
  module Testing
    module SetupAndTeardown
      def self.included(base)
        base.extend ClassMethods

        begin
          require 'mocha'
          base.alias_method_chain :run, :callbacks_and_mocha
        rescue LoadError
          base.alias_method_chain :run, :callbacks
        end
      end

      module ClassMethods
        def setup(*method_names, &block)
          method_names << block if block_given?
          (@setup_callbacks ||= []).concat method_names
        end

        def teardown(*method_names, &block)
          method_names << block if block_given?
          (@teardown_callbacks ||= []).concat method_names
        end

        def setup_callback_chain
          @setup_callbacks ||= []

          if superclass.respond_to?(:setup_callback_chain)
            superclass.setup_callback_chain + @setup_callbacks
          else
            @setup_callbacks
          end
        end

        def teardown_callback_chain
          @teardown_callbacks ||= []

          if superclass.respond_to?(:teardown_callback_chain)
            superclass.teardown_callback_chain + @teardown_callbacks
          else
            @teardown_callbacks
          end
        end
      end

      # This redefinition is unfortunate but test/unit shows us no alternative.
      def run_with_callbacks(result) #:nodoc:
        return if @method_name.to_s == "default_test"

        yield(Test::Unit::TestCase::STARTED, name)
        @_result = result
        begin
          run_callbacks :setup
          setup
          __send__(@method_name)
        rescue Test::Unit::AssertionFailedError => e
          add_failure(e.message, e.backtrace)
        rescue *Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS
          raise
        rescue Exception
          add_error($!)
        ensure
          begin
            teardown
            run_callbacks :teardown, :reverse_each
          rescue Test::Unit::AssertionFailedError => e
            add_failure(e.message, e.backtrace)
          rescue *Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS
            raise
          rescue Exception
            add_error($!)
          end
        end
        result.add_run
        yield(Test::Unit::TestCase::FINISHED, name)
      end

      # Doubly unfortunate: mocha does the same so we have to hax their hax.
      def run_with_callbacks_and_mocha(result)
        return if @method_name.to_s == "default_test"

        yield(Test::Unit::TestCase::STARTED, name)
        @_result = result
        begin
          mocha_setup
          begin
            run_callbacks :setup
            setup
            __send__(@method_name)
            mocha_verify { add_assertion }
          rescue Mocha::ExpectationError => e
            add_failure(e.message, e.backtrace)
          rescue Test::Unit::AssertionFailedError => e
            add_failure(e.message, e.backtrace)
          rescue StandardError, ScriptError
            add_error($!)
          ensure
            begin
              teardown
              run_callbacks :teardown, :reverse_each
            rescue Test::Unit::AssertionFailedError => e
              add_failure(e.message, e.backtrace)
            rescue StandardError, ScriptError
              add_error($!)
            end
          end
        ensure
          mocha_teardown
        end
        result.add_run
        yield(Test::Unit::TestCase::FINISHED, name)
      end

      protected
        def run_callbacks(kind, enumerator = :each)
          self.class.send("#{kind}_callback_chain").send(enumerator) do |callback|
            case callback
            when Proc; callback.call(self)
            when String, Symbol; send!(callback)
            else raise ArgumentError, "Unrecognized callback #{callback.inspect}"
            end
          end
        end
    end
  end
end