[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / test / test_forwardable.rb
blob9ed330058a7145c1c4301933bc2c2e7f920b0f31
1 # frozen_string_literal: false
2 require 'test/unit'
3 require 'forwardable'
5 class TestForwardable < Test::Unit::TestCase
6   INTEGER = 42
7   RECEIVER = BasicObject.new
8   RETURNED1 = BasicObject.new
9   RETURNED2 = BasicObject.new
11   class << RECEIVER
12     def delegated1
13       RETURNED1
14     end
16     def delegated2
17       RETURNED2
18     end
20     def delegated1_kw(**kw)
21       [RETURNED1, kw]
22     end
23   end
25   def test_def_instance_delegator
26     %i[def_delegator def_instance_delegator].each do |m|
27       ret = nil
28       cls = forwardable_class do
29         ret = __send__ m, :@receiver, :delegated1
30       end
32       assert_same RETURNED1, cls.new.delegated1
33       assert_equal :delegated1, ret
34     end
35   end
37   def test_def_instance_delegator_constant
38     %i[def_delegator def_instance_delegator].each do |m|
39       cls = forwardable_class do
40         __send__ m, 'TestForwardable::INTEGER', :to_i
41       end
43       assert_equal 42, cls.new.to_i
44     end
45   end
47   def test_def_instance_delegator_kw
48     %i[def_delegator def_instance_delegator].each do |m|
49       cls = forwardable_class do
50         __send__ m, :@receiver, :delegated1_kw
51       end
53       ary = cls.new.delegated1_kw b: 1
54       assert_same RETURNED1, ary[0]
55       assert_equal({b: 1}, ary[1])
56     end
57   end
59   def test_def_instance_delegator_using_args_method_as_receiver
60     %i[def_delegator def_instance_delegator].each do |m|
61       cls = forwardable_class(
62         receiver_name: :args,
63         type: :method,
64         visibility: :private
65       ) do
66         __send__ m, :args, :delegated1
67       end
69       assert_same RETURNED1, cls.new.delegated1
70     end
71   end
73   def test_def_instance_delegator_using_block_method_as_receiver
74     %i[def_delegator def_instance_delegator].each do |m|
75       cls = forwardable_class(
76         receiver_name: :block,
77         type: :method,
78         visibility: :private
79       ) do
80         __send__ m, :block, :delegated1
81       end
83       assert_same RETURNED1, cls.new.delegated1
84     end
85   end
87   def test_def_instance_delegators
88     %i[def_delegators def_instance_delegators].each do |m|
89       cls = forwardable_class do
90         __send__ m, :@receiver, :delegated1, :delegated2
91       end
93       assert_same RETURNED1, cls.new.delegated1
94       assert_same RETURNED2, cls.new.delegated2
95     end
96   end
98   def test_def_instance_delegators_using_args_method_as_receiver
99     %i[def_delegators def_instance_delegators].each do |m|
100       cls = forwardable_class(
101         receiver_name: :args,
102         type: :method,
103         visibility: :private
104       ) do
105         __send__ m, :args, :delegated1, :delegated2
106       end
108       assert_same RETURNED1, cls.new.delegated1
109       assert_same RETURNED2, cls.new.delegated2
110     end
111   end
113   def test_def_instance_delegators_using_block_method_as_receiver
114     %i[def_delegators def_instance_delegators].each do |m|
115       cls = forwardable_class(
116         receiver_name: :block,
117         type: :method,
118         visibility: :private
119       ) do
120         __send__ m, :block, :delegated1, :delegated2
121       end
123       assert_same RETURNED1, cls.new.delegated1
124       assert_same RETURNED2, cls.new.delegated2
125     end
126   end
128   def test_def_instance_delegators_send_id
129     %i[def_delegators def_instance_delegators].each do |m|
130       cls = forwardable_class do
131         attr_reader :receiver
132         __send__ m, :@receiver, :__send__, :__id__
133       end
135       assert_not_equal cls.new.__id__, cls.new.receiver.__id__
136       assert_not_equal cls.new.__send__(:__id__), cls.new.receiver.__send__(:__id__)
137     end
138   end
140   def test_instance_delegate
141     %i[delegate instance_delegate].each do |m|
142       cls = forwardable_class do
143         __send__ m, delegated1: :@receiver, delegated2: :@receiver
144       end
146       assert_same RETURNED1, cls.new.delegated1
147       assert_same RETURNED2, cls.new.delegated2
149       cls = forwardable_class do
150         __send__ m, %i[delegated1 delegated2] => :@receiver
151       end
153       assert_same RETURNED1, cls.new.delegated1
154       assert_same RETURNED2, cls.new.delegated2
155     end
156   end
158   def test_def_instance_delegate_using_args_method_as_receiver
159     %i[delegate instance_delegate].each do |m|
160       cls = forwardable_class(
161         receiver_name: :args,
162         type: :method,
163         visibility: :private
164       ) do
165         __send__ m, delegated1: :args, delegated2: :args
166       end
168       assert_same RETURNED1, cls.new.delegated1
169       assert_same RETURNED2, cls.new.delegated2
170     end
171   end
173   def test_def_instance_delegate_using_block_method_as_receiver
174     %i[delegate instance_delegate].each do |m|
175       cls = forwardable_class(
176         receiver_name: :block,
177         type: :method,
178         visibility: :private
179       ) do
180         __send__ m, delegated1: :block, delegated2: :block
181       end
183       assert_same RETURNED1, cls.new.delegated1
184       assert_same RETURNED2, cls.new.delegated2
185     end
186   end
188   def test_class_single_delegator
189     %i[def_delegator def_single_delegator].each do |m|
190       ret = nil
191       cls = single_forwardable_class do
192         ret = __send__ m, :@receiver, :delegated1
193       end
195       assert_same RETURNED1, cls.delegated1
196       assert_equal :delegated1, ret
197     end
198   end
200   def test_class_single_delegators
201     %i[def_delegators def_single_delegators].each do |m|
202       cls = single_forwardable_class do
203         __send__ m, :@receiver, :delegated1, :delegated2
204       end
206       assert_same RETURNED1, cls.delegated1
207       assert_same RETURNED2, cls.delegated2
208     end
209   end
211   def test_class_single_delegate
212     %i[delegate single_delegate].each do |m|
213       cls = single_forwardable_class do
214         __send__ m, delegated1: :@receiver, delegated2: :@receiver
215       end
217       assert_same RETURNED1, cls.delegated1
218       assert_same RETURNED2, cls.delegated2
220       cls = single_forwardable_class do
221         __send__ m, %i[delegated1 delegated2] => :@receiver
222       end
224       assert_same RETURNED1, cls.delegated1
225       assert_same RETURNED2, cls.delegated2
226     end
227   end
229   def test_obj_single_delegator
230     %i[def_delegator def_single_delegator].each do |m|
231       obj = single_forwardable_object do
232         __send__ m, :@receiver, :delegated1
233       end
235       assert_same RETURNED1, obj.delegated1
236     end
237   end
239   def test_obj_single_delegators
240     %i[def_delegators def_single_delegators].each do |m|
241       obj = single_forwardable_object do
242         __send__ m, :@receiver, :delegated1, :delegated2
243       end
245       assert_same RETURNED1, obj.delegated1
246       assert_same RETURNED2, obj.delegated2
247     end
248   end
250   def test_obj_single_delegators_send_id
251     %i[def_delegators def_single_delegators].each do |m|
252       obj = single_forwardable_object do
253         singleton_class.__send__ :attr_reader, :receiver
254         __send__ m, :@receiver, :__send__, :__id__
255       end
257       assert_not_equal obj.__id__, obj.receiver.__id__
258       assert_not_equal obj.__send__(:__id__), obj.receiver.__send__(:__id__)
259     end
260   end
262   def test_obj_single_delegate
263     %i[delegate single_delegate].each do |m|
264       obj = single_forwardable_object do
265         __send__ m, delegated1: :@receiver, delegated2: :@receiver
266       end
268       assert_same RETURNED1, obj.delegated1
269       assert_same RETURNED2, obj.delegated2
271       obj = single_forwardable_object do
272         __send__ m, %i[delegated1 delegated2] => :@receiver
273       end
275       assert_same RETURNED1, obj.delegated1
276       assert_same RETURNED2, obj.delegated2
277     end
278   end
280   class Foo
281     extend Forwardable
283     attr_accessor :bar
284     def_delegator :bar, :baz
285     def_delegator :caller, :itself, :c
286   end
288   def test_backtrace_adjustment
289     obj = Foo.new
290     def (obj.bar = Object.new).baz
291       foo
292     end
293     e = assert_raise(NameError) {
294       obj.baz
295     }
296     assert_not_match(/\/forwardable\.rb/, e.backtrace[0],
297                      proc {RubyVM::InstructionSequence.of(obj.method(:baz)).disassemble})
298     assert_equal(caller(0, 1)[0], Foo.new.c[0])
299   end
301   class Foo2 < BasicObject
302     extend ::Forwardable
304     def_delegator :bar, :baz
305   end
307   def test_basicobject_subclass
308     bug11616 = '[ruby-core:71176] [Bug #11616]'
309     assert_raise_with_message(NameError, /[`']bar'/, bug11616) {
310       Foo2.new.baz
311     }
312   end
314   def test_aref
315     obj = Object.new.extend SingleForwardable
316     obj.instance_variable_set("@h", {foo: 42})
317     obj.def_delegator("@h", :[])
318     assert_equal(42, obj[:foo])
319   end
321   def test_aset
322     obj = Object.new.extend SingleForwardable
323     obj.instance_variable_set("@h", h = {foo: 0})
324     obj.def_delegator("@h", :[]=)
325     obj[:foo] = 42
326     assert_equal(42, h[:foo])
327   end
329   def test_binop
330     obj = Object.new.extend SingleForwardable
331     obj.instance_variable_set("@h", 40)
332     obj.def_delegator("@h", :+)
333     assert_equal(42, obj+2)
334   end
336   def test_uniop
337     obj = Object.new.extend SingleForwardable
338     obj.instance_variable_set("@h", -42)
339     obj.def_delegator("@h", :-@)
340     assert_equal(42, -obj)
341   end
343   def test_on_private_method
344     cls = Class.new do
345       private def foo; :foo end
346       extend Forwardable
347       def_delegator :itself, :foo, :bar
348     end
349     assert_warn(/forwarding to private method/) do
350       assert_equal(:foo, cls.new.bar)
351     end
352   end
354   def test_non_module
355     str = String.new
356     str.extend Forwardable
357     str.instance_variable_set("@h", 42)
358     str.def_delegator("@h", :to_s, :forty_two)
359     assert_equal("42", str.forty_two)
360   end
362   private
364   def forwardable_class(
365     receiver_name: :receiver,
366     type: :ivar,
367     visibility: :public,
368     &block
369   )
370     Class.new do
371       extend Forwardable
373       define_method(:initialize) do
374         instance_variable_set("@#{receiver_name}", RECEIVER)
375       end
377       if type == :method
378         attr_reader(receiver_name)
379         __send__(visibility, receiver_name)
380       end
382       class_exec(&block)
383     end
384   end
386   def single_forwardable_class(&block)
387     Class.new do
388       extend SingleForwardable
390       @receiver = RECEIVER
392       class_exec(&block)
393     end
394   end
396   def single_forwardable_object(&block)
397     obj = Object.new.extend SingleForwardable
398     obj.instance_variable_set(:@receiver, RECEIVER)
399     obj.instance_eval(&block)
400     obj
401   end