$:.unshift File.dirname(__FILE__) + "/../lib" require 'minitest/autorun' require 'rgen/util/method_delegation' class MethodDelegationTest < MiniTest::Test include RGen class TestDelegate attr_accessor :mode, :callcount def common_delegated(delegator) @callcount ||= 0 @callcount += 1 case @mode when :continue throw :continue when :delegatorId delegator.object_id when :return7 7 end end alias to_s_delegated common_delegated alias methodInSingleton_delegated common_delegated alias class_delegated common_delegated alias artificialMethod_delegated common_delegated end class ConstPathElement < Module def self.const_missing_delegated(delegator, const) ConstPathElement.new(const) end def initialize(name, parent=nil) @name = name.to_s @parent = parent end def const_missing(const) ConstPathElement.new(const, self) end def to_s if @parent @parent.to_s+"::"+@name else @name end end end # missing: check with multiple params and block param def test_method_defined_in_singleton # delegator is an Array delegator = [] # delegating method is a method defined in the singleton class class << delegator def methodInSingleton "result from method in singleton" end end checkDelegation(delegator, "methodInSingleton", "result from method in singleton") end def test_method_defined_in_class # delegator is a String delegator = "Delegator1" checkDelegation(delegator, "to_s", "Delegator1") end def test_method_defined_in_superclass # delegator is an instance of a new anonymous class delegator = Class.new.new # delegating method is +object_id+ which is defined in the superclass checkDelegation(delegator, "class", delegator.class) end def test_new_method # delegator is an String delegator = "Delegator2" # delegating method is a new method which does not exist on String checkDelegation(delegator, "artificialMethod", delegator.object_id, true) end def test_const_missing surroundingModule = Module.nesting.first Util::MethodDelegation.registerDelegate(ConstPathElement, surroundingModule, "const_missing") assert_equal "SomeArbitraryConst", SomeArbitraryConst.to_s assert_equal "AnotherConst::A::B::C", AnotherConst::A::B::C.to_s Util::MethodDelegation.unregisterDelegate(ConstPathElement, surroundingModule, "const_missing") assert_raises NameError do SomeArbitraryConst end end def checkDelegation(delegator, method, originalResult, newMethod=false) delegate1 = TestDelegate.new delegate2 = TestDelegate.new Util::MethodDelegation.registerDelegate(delegate1, delegator, method) Util::MethodDelegation.registerDelegate(delegate2, delegator, method) assert delegator.respond_to?(:_methodDelegates) if newMethod assert !delegator.respond_to?("#{method}_delegate_original".to_sym) else assert delegator.respond_to?("#{method}_delegate_original".to_sym) end # check delegator parameter delegate1.mode = :delegatorId assert_equal delegator.object_id, delegator.send(method) delegate1.callcount = 0 delegate2.callcount = 0 delegate1.mode = :return7 # delegate1 returns a value assert_equal 7, delegator.send(method) assert_equal 1, delegate1.callcount # delegate2 is not called assert_equal 0, delegate2.callcount delegate1.mode = :nothing # delegate1 just exits and thus returns nil assert_nil delegator.send(method) assert_equal 2, delegate1.callcount # delegate2 is not called assert_equal 0, delegate2.callcount delegate1.mode = :continue delegate2.mode = :return7 # delegate1 is called but continues # delegate2 returns a value assert_equal 7, delegator.send(method) assert_equal 3, delegate1.callcount assert_equal 1, delegate2.callcount delegate1.mode = :continue delegate2.mode = :continue # both delegates continue, the original method returns its value checkCallOriginal(delegator, method, originalResult, newMethod) # both delegates are called though assert_equal 4, delegate1.callcount assert_equal 2, delegate2.callcount # calling unregister with a non existing method has no effect Util::MethodDelegation.unregisterDelegate(delegate1, delegator, "xxx") Util::MethodDelegation.unregisterDelegate(delegate1, delegator, method) checkCallOriginal(delegator, method, originalResult, newMethod) # delegate1 not called any more assert_equal 4, delegate1.callcount # delegate2 is still called assert_equal 3, delegate2.callcount Util::MethodDelegation.unregisterDelegate(delegate2, delegator, method) checkCallOriginal(delegator, method, originalResult, newMethod) # both delegates not called any more assert_equal 4, delegate1.callcount assert_equal 3, delegate2.callcount # after all delegates were unregistered, singleton class should be clean assert !delegator.respond_to?(:_methodDelegates) end def checkCallOriginal(delegator, method, originalResult, newMethod) if newMethod assert_raises NoMethodError do result = delegator.send(method) end else result = delegator.send(method) assert_equal originalResult, result end end end