summaryrefslogtreecommitdiff
path: root/test/test_forwardable.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_forwardable.rb')
-rw-r--r--test/test_forwardable.rb402
1 files changed, 402 insertions, 0 deletions
diff --git a/test/test_forwardable.rb b/test/test_forwardable.rb
new file mode 100644
index 0000000000..9ed330058a
--- /dev/null
+++ b/test/test_forwardable.rb
@@ -0,0 +1,402 @@
+# frozen_string_literal: false
+require 'test/unit'
+require 'forwardable'
+
+class TestForwardable < Test::Unit::TestCase
+ INTEGER = 42
+ RECEIVER = BasicObject.new
+ RETURNED1 = BasicObject.new
+ RETURNED2 = BasicObject.new
+
+ class << RECEIVER
+ def delegated1
+ RETURNED1
+ end
+
+ def delegated2
+ RETURNED2
+ end
+
+ def delegated1_kw(**kw)
+ [RETURNED1, kw]
+ end
+ end
+
+ def test_def_instance_delegator
+ %i[def_delegator def_instance_delegator].each do |m|
+ ret = nil
+ cls = forwardable_class do
+ ret = __send__ m, :@receiver, :delegated1
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ assert_equal :delegated1, ret
+ end
+ end
+
+ def test_def_instance_delegator_constant
+ %i[def_delegator def_instance_delegator].each do |m|
+ cls = forwardable_class do
+ __send__ m, 'TestForwardable::INTEGER', :to_i
+ end
+
+ assert_equal 42, cls.new.to_i
+ end
+ end
+
+ def test_def_instance_delegator_kw
+ %i[def_delegator def_instance_delegator].each do |m|
+ cls = forwardable_class do
+ __send__ m, :@receiver, :delegated1_kw
+ end
+
+ ary = cls.new.delegated1_kw b: 1
+ assert_same RETURNED1, ary[0]
+ assert_equal({b: 1}, ary[1])
+ end
+ end
+
+ def test_def_instance_delegator_using_args_method_as_receiver
+ %i[def_delegator def_instance_delegator].each do |m|
+ cls = forwardable_class(
+ receiver_name: :args,
+ type: :method,
+ visibility: :private
+ ) do
+ __send__ m, :args, :delegated1
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ end
+ end
+
+ def test_def_instance_delegator_using_block_method_as_receiver
+ %i[def_delegator def_instance_delegator].each do |m|
+ cls = forwardable_class(
+ receiver_name: :block,
+ type: :method,
+ visibility: :private
+ ) do
+ __send__ m, :block, :delegated1
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ end
+ end
+
+ def test_def_instance_delegators
+ %i[def_delegators def_instance_delegators].each do |m|
+ cls = forwardable_class do
+ __send__ m, :@receiver, :delegated1, :delegated2
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ assert_same RETURNED2, cls.new.delegated2
+ end
+ end
+
+ def test_def_instance_delegators_using_args_method_as_receiver
+ %i[def_delegators def_instance_delegators].each do |m|
+ cls = forwardable_class(
+ receiver_name: :args,
+ type: :method,
+ visibility: :private
+ ) do
+ __send__ m, :args, :delegated1, :delegated2
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ assert_same RETURNED2, cls.new.delegated2
+ end
+ end
+
+ def test_def_instance_delegators_using_block_method_as_receiver
+ %i[def_delegators def_instance_delegators].each do |m|
+ cls = forwardable_class(
+ receiver_name: :block,
+ type: :method,
+ visibility: :private
+ ) do
+ __send__ m, :block, :delegated1, :delegated2
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ assert_same RETURNED2, cls.new.delegated2
+ end
+ end
+
+ def test_def_instance_delegators_send_id
+ %i[def_delegators def_instance_delegators].each do |m|
+ cls = forwardable_class do
+ attr_reader :receiver
+ __send__ m, :@receiver, :__send__, :__id__
+ end
+
+ assert_not_equal cls.new.__id__, cls.new.receiver.__id__
+ assert_not_equal cls.new.__send__(:__id__), cls.new.receiver.__send__(:__id__)
+ end
+ end
+
+ def test_instance_delegate
+ %i[delegate instance_delegate].each do |m|
+ cls = forwardable_class do
+ __send__ m, delegated1: :@receiver, delegated2: :@receiver
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ assert_same RETURNED2, cls.new.delegated2
+
+ cls = forwardable_class do
+ __send__ m, %i[delegated1 delegated2] => :@receiver
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ assert_same RETURNED2, cls.new.delegated2
+ end
+ end
+
+ def test_def_instance_delegate_using_args_method_as_receiver
+ %i[delegate instance_delegate].each do |m|
+ cls = forwardable_class(
+ receiver_name: :args,
+ type: :method,
+ visibility: :private
+ ) do
+ __send__ m, delegated1: :args, delegated2: :args
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ assert_same RETURNED2, cls.new.delegated2
+ end
+ end
+
+ def test_def_instance_delegate_using_block_method_as_receiver
+ %i[delegate instance_delegate].each do |m|
+ cls = forwardable_class(
+ receiver_name: :block,
+ type: :method,
+ visibility: :private
+ ) do
+ __send__ m, delegated1: :block, delegated2: :block
+ end
+
+ assert_same RETURNED1, cls.new.delegated1
+ assert_same RETURNED2, cls.new.delegated2
+ end
+ end
+
+ def test_class_single_delegator
+ %i[def_delegator def_single_delegator].each do |m|
+ ret = nil
+ cls = single_forwardable_class do
+ ret = __send__ m, :@receiver, :delegated1
+ end
+
+ assert_same RETURNED1, cls.delegated1
+ assert_equal :delegated1, ret
+ end
+ end
+
+ def test_class_single_delegators
+ %i[def_delegators def_single_delegators].each do |m|
+ cls = single_forwardable_class do
+ __send__ m, :@receiver, :delegated1, :delegated2
+ end
+
+ assert_same RETURNED1, cls.delegated1
+ assert_same RETURNED2, cls.delegated2
+ end
+ end
+
+ def test_class_single_delegate
+ %i[delegate single_delegate].each do |m|
+ cls = single_forwardable_class do
+ __send__ m, delegated1: :@receiver, delegated2: :@receiver
+ end
+
+ assert_same RETURNED1, cls.delegated1
+ assert_same RETURNED2, cls.delegated2
+
+ cls = single_forwardable_class do
+ __send__ m, %i[delegated1 delegated2] => :@receiver
+ end
+
+ assert_same RETURNED1, cls.delegated1
+ assert_same RETURNED2, cls.delegated2
+ end
+ end
+
+ def test_obj_single_delegator
+ %i[def_delegator def_single_delegator].each do |m|
+ obj = single_forwardable_object do
+ __send__ m, :@receiver, :delegated1
+ end
+
+ assert_same RETURNED1, obj.delegated1
+ end
+ end
+
+ def test_obj_single_delegators
+ %i[def_delegators def_single_delegators].each do |m|
+ obj = single_forwardable_object do
+ __send__ m, :@receiver, :delegated1, :delegated2
+ end
+
+ assert_same RETURNED1, obj.delegated1
+ assert_same RETURNED2, obj.delegated2
+ end
+ end
+
+ def test_obj_single_delegators_send_id
+ %i[def_delegators def_single_delegators].each do |m|
+ obj = single_forwardable_object do
+ singleton_class.__send__ :attr_reader, :receiver
+ __send__ m, :@receiver, :__send__, :__id__
+ end
+
+ assert_not_equal obj.__id__, obj.receiver.__id__
+ assert_not_equal obj.__send__(:__id__), obj.receiver.__send__(:__id__)
+ end
+ end
+
+ def test_obj_single_delegate
+ %i[delegate single_delegate].each do |m|
+ obj = single_forwardable_object do
+ __send__ m, delegated1: :@receiver, delegated2: :@receiver
+ end
+
+ assert_same RETURNED1, obj.delegated1
+ assert_same RETURNED2, obj.delegated2
+
+ obj = single_forwardable_object do
+ __send__ m, %i[delegated1 delegated2] => :@receiver
+ end
+
+ assert_same RETURNED1, obj.delegated1
+ assert_same RETURNED2, obj.delegated2
+ end
+ end
+
+ class Foo
+ extend Forwardable
+
+ attr_accessor :bar
+ def_delegator :bar, :baz
+ def_delegator :caller, :itself, :c
+ end
+
+ def test_backtrace_adjustment
+ obj = Foo.new
+ def (obj.bar = Object.new).baz
+ foo
+ end
+ e = assert_raise(NameError) {
+ obj.baz
+ }
+ assert_not_match(/\/forwardable\.rb/, e.backtrace[0],
+ proc {RubyVM::InstructionSequence.of(obj.method(:baz)).disassemble})
+ assert_equal(caller(0, 1)[0], Foo.new.c[0])
+ end
+
+ class Foo2 < BasicObject
+ extend ::Forwardable
+
+ def_delegator :bar, :baz
+ end
+
+ def test_basicobject_subclass
+ bug11616 = '[ruby-core:71176] [Bug #11616]'
+ assert_raise_with_message(NameError, /[`']bar'/, bug11616) {
+ Foo2.new.baz
+ }
+ end
+
+ def test_aref
+ obj = Object.new.extend SingleForwardable
+ obj.instance_variable_set("@h", {foo: 42})
+ obj.def_delegator("@h", :[])
+ assert_equal(42, obj[:foo])
+ end
+
+ def test_aset
+ obj = Object.new.extend SingleForwardable
+ obj.instance_variable_set("@h", h = {foo: 0})
+ obj.def_delegator("@h", :[]=)
+ obj[:foo] = 42
+ assert_equal(42, h[:foo])
+ end
+
+ def test_binop
+ obj = Object.new.extend SingleForwardable
+ obj.instance_variable_set("@h", 40)
+ obj.def_delegator("@h", :+)
+ assert_equal(42, obj+2)
+ end
+
+ def test_uniop
+ obj = Object.new.extend SingleForwardable
+ obj.instance_variable_set("@h", -42)
+ obj.def_delegator("@h", :-@)
+ assert_equal(42, -obj)
+ end
+
+ def test_on_private_method
+ cls = Class.new do
+ private def foo; :foo end
+ extend Forwardable
+ def_delegator :itself, :foo, :bar
+ end
+ assert_warn(/forwarding to private method/) do
+ assert_equal(:foo, cls.new.bar)
+ end
+ end
+
+ def test_non_module
+ str = String.new
+ str.extend Forwardable
+ str.instance_variable_set("@h", 42)
+ str.def_delegator("@h", :to_s, :forty_two)
+ assert_equal("42", str.forty_two)
+ end
+
+ private
+
+ def forwardable_class(
+ receiver_name: :receiver,
+ type: :ivar,
+ visibility: :public,
+ &block
+ )
+ Class.new do
+ extend Forwardable
+
+ define_method(:initialize) do
+ instance_variable_set("@#{receiver_name}", RECEIVER)
+ end
+
+ if type == :method
+ attr_reader(receiver_name)
+ __send__(visibility, receiver_name)
+ end
+
+ class_exec(&block)
+ end
+ end
+
+ def single_forwardable_class(&block)
+ Class.new do
+ extend SingleForwardable
+
+ @receiver = RECEIVER
+
+ class_exec(&block)
+ end
+ end
+
+ def single_forwardable_object(&block)
+ obj = Object.new.extend SingleForwardable
+ obj.instance_variable_set(:@receiver, RECEIVER)
+ obj.instance_eval(&block)
+ obj
+ end
+end