diff options
Diffstat (limited to 'activesupport/test/callbacks_test.rb')
-rw-r--r-- | activesupport/test/callbacks_test.rb | 366 |
1 files changed, 328 insertions, 38 deletions
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index 8810302f40..32c2dfdfc0 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -1,27 +1,6 @@ require 'abstract_unit' module CallbacksTest - class Phone - include ActiveSupport::Callbacks - define_callbacks :save - - set_callback :save, :before, :before_save1 - set_callback :save, :after, :after_save1 - - def before_save1; self.history << :before; end - def after_save1; self.history << :after; end - - def save - run_callbacks :save do - raise 'boom' - end - end - - def history - @history ||= [] - end - end - class Record include ActiveSupport::Callbacks @@ -66,6 +45,16 @@ module CallbacksTest end end + class CallbackClass + def self.before(model) + model.history << [:before_save, :class] + end + + def self.after(model) + model.history << [:after_save, :class] + end + end + class Person < Record [:before_save, :after_save].each do |callback_method| callback_method_sym = callback_method.to_sym @@ -73,6 +62,7 @@ module CallbacksTest send(callback_method, callback_string(callback_method_sym)) send(callback_method, callback_proc(callback_method_sym)) send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, ''))) + send(callback_method, CallbackClass) send(callback_method) { |model| model.history << [callback_method_sym, :block] } end @@ -86,10 +76,14 @@ module CallbacksTest skip_callback :save, :after, :before_save_method, :unless => :yes skip_callback :save, :after, :before_save_method, :if => :no skip_callback :save, :before, :before_save_method, :unless => :no + skip_callback :save, :before, CallbackClass , :if => :yes def yes; true; end def no; false; end end + class PersonForProgrammaticSkipping < Person + end + class ParentController include ActiveSupport::Callbacks @@ -297,7 +291,7 @@ module CallbacksTest end end end - + class AroundPersonResult < MySuper attr_reader :result @@ -308,7 +302,7 @@ module CallbacksTest def tweedle_dum @result = yield end - + def tweedle_1 :tweedle_1 end @@ -316,7 +310,7 @@ module CallbacksTest def tweedle_2 :tweedle_2 end - + def save run_callbacks :save do :running @@ -410,7 +404,7 @@ module CallbacksTest ], around.history end end - + class AroundCallbackResultTest < ActiveSupport::TestCase def test_save_around around = AroundPersonResult.new @@ -430,6 +424,26 @@ module CallbacksTest [:before_save, :object], [:before_save, :block], [:after_save, :block], + [:after_save, :class], + [:after_save, :object], + [:after_save, :proc], + [:after_save, :string], + [:after_save, :symbol] + ], person.history + end + + def test_skip_person_programmatically + PersonForProgrammaticSkipping._save_callbacks.each do |save_callback| + if "before" == save_callback.kind.to_s + PersonForProgrammaticSkipping.skip_callback("save", save_callback.kind, save_callback.filter) + end + end + person = PersonForProgrammaticSkipping.new + assert_equal [], person.history + person.save + assert_equal [ + [:after_save, :block], + [:after_save, :class], [:after_save, :object], [:after_save, :proc], [:after_save, :string], @@ -449,8 +463,10 @@ module CallbacksTest [:before_save, :string], [:before_save, :proc], [:before_save, :object], + [:before_save, :class], [:before_save, :block], [:after_save, :block], + [:after_save, :class], [:after_save, :object], [:after_save, :proc], [:after_save, :string], @@ -488,7 +504,7 @@ module CallbacksTest class CallbackTerminator include ActiveSupport::Callbacks - define_callbacks :save, :terminator => "result == :halt" + define_callbacks :save, :terminator => ->(_,result) { result == :halt } set_callback :save, :before, :first set_callback :save, :before, :second @@ -607,6 +623,45 @@ module CallbacksTest end end + class OneTwoThreeSave + include ActiveSupport::Callbacks + + define_callbacks :save + + attr_accessor :record + + def initialize + @record = [] + end + + def save + run_callbacks :save do + @record << "yielded" + end + end + + def first + @record << "one" + end + + def second + @record << "two" + end + + def third + @record << "three" + end + end + + class DuplicatingCallbacks < OneTwoThreeSave + set_callback :save, :before, :first, :second + set_callback :save, :before, :first, :third + end + + class DuplicatingCallbacksInSameCall < OneTwoThreeSave + set_callback :save, :before, :first, :second, :first, :third + end + class UsingObjectTest < ActiveSupport::TestCase def test_before_object u = UsingObjectBefore.new @@ -642,7 +697,7 @@ module CallbacksTest def test_termination_invokes_hook terminator = CallbackTerminator.new terminator.save - assert_equal ":second", terminator.halted + assert_equal :second, terminator.halted end def test_block_never_called_if_terminated @@ -676,8 +731,10 @@ module CallbacksTest [:before_save, :string], [:before_save, :proc], [:before_save, :object], + [:before_save, :class], [:before_save, :block], [:after_save, :block], + [:after_save, :class], [:after_save, :object], [:after_save, :proc], [:after_save, :string], @@ -694,20 +751,253 @@ module CallbacksTest end end - class PerKeyOptionDeprecationTest < ActiveSupport::TestCase + class ExcludingDuplicatesCallbackTest < ActiveSupport::TestCase + def test_excludes_duplicates_in_separate_calls + model = DuplicatingCallbacks.new + model.save + assert_equal ["two", "one", "three", "yielded"], model.record + end - def test_per_key_option_deprecaton - assert_raise NotImplementedError do - Phone.class_eval do - set_callback :save, :before, :before_save1, :per_key => {:if => "true"} - end + def test_excludes_duplicates_in_one_call + model = DuplicatingCallbacksInSameCall.new + model.save + assert_equal ["two", "one", "three", "yielded"], model.record + end + end + + class CallbackProcTest < ActiveSupport::TestCase + def build_class(callback) + Class.new { + include ActiveSupport::Callbacks + define_callbacks :foo + set_callback :foo, :before, callback + def run; run_callbacks :foo; end + } + end + + def test_proc_arity_0 + calls = [] + klass = build_class(->() { calls << :foo }) + klass.new.run + assert_equal [:foo], calls + end + + def test_proc_arity_1 + calls = [] + klass = build_class(->(o) { calls << o }) + instance = klass.new + instance.run + assert_equal [instance], calls + end + + def test_proc_arity_2 + assert_raises(ArgumentError) do + klass = build_class(->(x,y) { }) + klass.new.run end - assert_raise NotImplementedError do - Phone.class_eval do - skip_callback :save, :before, :before_save1, :per_key => {:if => "true"} - end + end + + def test_proc_negative_called_with_empty_list + calls = [] + klass = build_class(->(*args) { calls << args }) + klass.new.run + assert_equal [[]], calls + end + end + + class ConditionalTests < ActiveSupport::TestCase + def build_class(callback) + Class.new { + include ActiveSupport::Callbacks + define_callbacks :foo + set_callback :foo, :before, :foo, :if => callback + def foo; end + def run; run_callbacks :foo; end + } + end + + # FIXME: do we really want to support classes as conditionals? There were + # no tests for it previous to this. + def test_class_conditional_with_scope + z = [] + callback = Class.new { + define_singleton_method(:foo) { |o| z << o } + } + klass = Class.new { + include ActiveSupport::Callbacks + define_callbacks :foo, :scope => [:name] + set_callback :foo, :before, :foo, :if => callback + def run; run_callbacks :foo; end + private + def foo; end + } + object = klass.new + object.run + assert_equal [object], z + end + + # FIXME: do we really want to support classes as conditionals? There were + # no tests for it previous to this. + def test_class + z = [] + klass = build_class Class.new { + define_singleton_method(:before) { |o| z << o } + } + object = klass.new + object.run + assert_equal [object], z + end + + def test_proc_negative_arity # passes an empty list if *args + z = [] + object = build_class(->(*args) { z << args }).new + object.run + assert_equal [], z.flatten + end + + def test_proc_arity0 + z = [] + object = build_class(->() { z << 0 }).new + object.run + assert_equal [0], z + end + + def test_proc_arity1 + z = [] + object = build_class(->(x) { z << x }).new + object.run + assert_equal [object], z + end + + def test_proc_arity2 + assert_raises(ArgumentError) do + object = build_class(->(a,b) { }).new + object.run end end end - + + class ResetCallbackTest < ActiveSupport::TestCase + def build_class(memo) + klass = Class.new { + include ActiveSupport::Callbacks + define_callbacks :foo + set_callback :foo, :before, :hello + def run; run_callbacks :foo; end + } + klass.class_eval { + define_method(:hello) { memo << :hi } + } + klass + end + + def test_reset_callbacks + events = [] + klass = build_class events + klass.new.run + assert_equal 1, events.length + + klass.reset_callbacks :foo + klass.new.run + assert_equal 1, events.length + end + + def test_reset_impacts_subclasses + events = [] + klass = build_class events + subclass = Class.new(klass) { set_callback :foo, :before, :world } + subclass.class_eval { define_method(:world) { events << :world } } + + subclass.new.run + assert_equal 2, events.length + + klass.reset_callbacks :foo + subclass.new.run + assert_equal 3, events.length + end + end + + class CallbackTypeTest < ActiveSupport::TestCase + def build_class(callback, n = 10) + Class.new { + include ActiveSupport::Callbacks + define_callbacks :foo + n.times { set_callback :foo, :before, callback } + def run; run_callbacks :foo; end + def self.skip(thing); skip_callback :foo, :before, thing; end + } + end + + def test_add_class + calls = [] + callback = Class.new { + define_singleton_method(:before) { |o| calls << o } + } + build_class(callback).new.run + assert_equal 10, calls.length + end + + def test_add_lambda + calls = [] + build_class(->(o) { calls << o }).new.run + assert_equal 10, calls.length + end + + def test_add_symbol + calls = [] + klass = build_class(:bar) + klass.class_eval { define_method(:bar) { calls << klass } } + klass.new.run + assert_equal 1, calls.length + end + + def test_add_eval + calls = [] + klass = build_class("bar") + klass.class_eval { define_method(:bar) { calls << klass } } + klass.new.run + assert_equal 1, calls.length + end + + def test_skip_class # removes one at a time + calls = [] + callback = Class.new { + define_singleton_method(:before) { |o| calls << o } + } + klass = build_class(callback) + 9.downto(0) { |i| + klass.skip callback + klass.new.run + assert_equal i, calls.length + calls.clear + } + end + + def test_skip_lambda # removes nothing + calls = [] + callback = ->(o) { calls << o } + klass = build_class(callback) + 10.times { klass.skip callback } + klass.new.run + assert_equal 10, calls.length + end + + def test_skip_symbol # removes all + calls = [] + klass = build_class(:bar) + klass.class_eval { define_method(:bar) { calls << klass } } + klass.skip :bar + klass.new.run + assert_equal 0, calls.length + end + + def test_skip_eval # removes nothing + calls = [] + klass = build_class("bar") + klass.class_eval { define_method(:bar) { calls << klass } } + klass.skip "bar" + klass.new.run + assert_equal 1, calls.length + end + end end |