summaryrefslogtreecommitdiff
path: root/test/ruby/test_method.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_method.rb')
-rw-r--r--test/ruby/test_method.rb1505
1 files changed, 1475 insertions, 30 deletions
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index 90f7ddacde..8561f841a8 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -1,10 +1,10 @@
+# -*- coding: us-ascii -*-
+# frozen_string_literal: false
require 'test/unit'
-require_relative 'envutil'
class TestMethod < Test::Unit::TestCase
def setup
@verbose = $VERBOSE
- $VERBOSE = nil
end
def teardown
@@ -21,7 +21,18 @@ class TestMethod < Test::Unit::TestCase
def mo5(a, *b, c) end
def mo6(a, *b, c, &d) end
def mo7(a, b = nil, *c, d, &e) end
- def ma1((a), &b) end
+ def mo8(a, b = nil, *, d, &e) end
+ def ma1((a), &b) nil && a end
+ def mk1(**) end
+ def mk2(**o) nil && o end
+ def mk3(a, **o) nil && o end
+ def mk4(a = nil, **o) nil && o end
+ def mk5(a, b = nil, **o) nil && o end
+ def mk6(a, b = nil, c, **o) nil && o end
+ def mk7(a, b = nil, *c, d, **o) nil && o end
+ def mk8(a, b = nil, *c, d, e:, f: nil, **o) nil && o end
+ def mnk(**nil) end
+ def mf(...) end
class Base
def foo() :base end
@@ -31,12 +42,16 @@ class TestMethod < Test::Unit::TestCase
end
class T
def initialize; end
+ def initialize_copy(*) super end
+ def initialize_clone(*) super end
+ def initialize_dup(*) super end
+ def respond_to_missing?(*) super end
def normal_method; end
end
module M
def func; end
module_function :func
- def meth; end
+ def meth; :meth end
end
def mv1() end
@@ -63,6 +78,13 @@ class TestMethod < Test::Unit::TestCase
assert_equal(-2, method(:mo4).arity)
assert_equal(-3, method(:mo5).arity)
assert_equal(-3, method(:mo6).arity)
+ assert_equal(-1, method(:mk1).arity)
+ assert_equal(-1, method(:mk2).arity)
+ assert_equal(-2, method(:mk3).arity)
+ assert_equal(-1, method(:mk4).arity)
+ assert_equal(-2, method(:mk5).arity)
+ assert_equal(-3, method(:mk6).arity)
+ assert_equal(-3, method(:mk7).arity)
end
def test_arity_special
@@ -81,6 +103,12 @@ class TestMethod < Test::Unit::TestCase
assert_raise(TypeError) do
um.bind(Base.new)
end
+
+ # cleanup
+ Derived.class_eval do
+ remove_method :foo
+ def foo() :derived; end
+ end
end
def test_callee
@@ -90,6 +118,25 @@ class TestMethod < Test::Unit::TestCase
assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m)
assert_equal(:m, Class.new {define_method(:m) {tap{return __method__}}}.new.m)
assert_nil(eval("class TestCallee; __method__; end"))
+
+ assert_equal(:test_callee, __callee__)
+ [
+ ["method", Class.new {def m; __callee__; end},],
+ ["block", Class.new {def m; tap{return __callee__}; end},],
+ ["define_method", Class.new {define_method(:m) {__callee__}}],
+ ["define_method block", Class.new {define_method(:m) {tap{return __callee__}}}],
+ ].each do |mesg, c|
+ c.class_eval {alias m2 m}
+ o = c.new
+ assert_equal(:m, o.m, mesg)
+ assert_equal(:m2, o.m2, mesg)
+ end
+ assert_nil(eval("class TestCallee; __callee__; end"))
+ end
+
+ def test_orphan_callee
+ c = Class.new{def foo; proc{__callee__}; end; alias alias_foo foo}
+ assert_equal(:alias_foo, c.new.alias_foo.call, '[Bug #11046]')
end
def test_method_in_define_method_block
@@ -123,6 +170,7 @@ class TestMethod < Test::Unit::TestCase
def o.foo; end
assert_nothing_raised { RubyVM::InstructionSequence.disasm(o.method(:foo)) }
assert_nothing_raised { RubyVM::InstructionSequence.disasm("x".method(:upcase)) }
+ assert_nothing_raised { RubyVM::InstructionSequence.disasm(method(:to_s).to_proc) }
end
def test_new
@@ -157,6 +205,49 @@ class TestMethod < Test::Unit::TestCase
o = Object.new
def o.foo; end
assert_kind_of(Integer, o.method(:foo).hash)
+ assert_equal(Array.instance_method(:map).hash, Array.instance_method(:collect).hash)
+ assert_kind_of(String, o.method(:foo).hash.to_s)
+ end
+
+ def test_hash_does_not_change_after_compaction
+ omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)
+
+ # iseq backed method
+ assert_separately([], <<~RUBY)
+ def a; end
+
+ # Need this method here because otherwise the iseq may be on the C stack
+ # which would get pinned and not move during compaction
+ def get_hash
+ method(:a).hash
+ end
+
+ hash = get_hash
+
+ GC.verify_compaction_references(expand_heap: true, toward: :empty)
+
+ assert_equal(hash, get_hash)
+ RUBY
+ end
+
+ def test_owner
+ c = Class.new do
+ def foo; end
+ end
+ assert_equal(c, c.instance_method(:foo).owner)
+ c2 = Class.new(c)
+ assert_equal(c, c2.instance_method(:foo).owner)
+ end
+
+ def test_owner_missing
+ c = Class.new do
+ def respond_to_missing?(name, bool)
+ name == :foo
+ end
+ end
+ c2 = Class.new(c)
+ assert_equal(c, c.new.method(:foo).owner)
+ assert_equal(c2, c2.new.method(:foo).owner)
end
def test_receiver_name_owner
@@ -168,6 +259,12 @@ class TestMethod < Test::Unit::TestCase
assert_equal(class << o; self; end, m.owner)
assert_equal(:foo, m.unbind.name)
assert_equal(class << o; self; end, m.unbind.owner)
+ class << o
+ alias bar foo
+ end
+ m = o.method(:bar)
+ assert_equal(:bar, m.name)
+ assert_equal(:foo, m.original_name)
end
def test_instance_method
@@ -185,6 +282,19 @@ class TestMethod < Test::Unit::TestCase
def o.bar; end
m = o.method(:bar).unbind
assert_raise(TypeError) { m.bind(Object.new) }
+
+ cx = EnvUtil.labeled_class("X\u{1f431}")
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /X\u{1f431}/) do
+ o.method(cx)
+ end
+ end
+ end
+
+ def test_bind_module_instance_method
+ feature4254 = '[ruby-core:34267]'
+ m = M.instance_method(:meth)
+ assert_equal(:meth, m.bind(Object.new).call, feature4254)
end
def test_define_method
@@ -208,18 +318,57 @@ class TestMethod < Test::Unit::TestCase
Class.new.class_eval { define_method(:bar, o.method(:bar)) }
end
+ cx = EnvUtil.labeled_class("X\u{1f431}")
+ EnvUtil.with_default_internal(Encoding::UTF_8) do
+ assert_raise_with_message(TypeError, /X\u{1F431}/) do
+ Class.new {define_method(cx) {}}
+ end
+ end
+ end
+
+ def test_define_method_no_proc
o = Object.new
def o.foo(c)
c.class_eval { define_method(:foo) }
end
c = Class.new
- o.foo(c) { :foo }
- assert_equal(:foo, c.new.foo)
+ assert_raise(ArgumentError) {o.foo(c)}
+ bug11283 = '[ruby-core:69655] [Bug #11283]'
+ assert_raise(ArgumentError, bug11283) {o.foo(c) {:foo}}
+ end
+
+ def test_define_singleton_method
o = Object.new
o.instance_eval { define_singleton_method(:foo) { :foo } }
assert_equal(:foo, o.foo)
+ end
+ PUBLIC_SINGLETON_TEST = Object.new
+ class << PUBLIC_SINGLETON_TEST
+ private
+ PUBLIC_SINGLETON_TEST.define_singleton_method(:dsm){}
+ def PUBLIC_SINGLETON_TEST.def; end
+ end
+ def test_define_singleton_method_public
+ assert_nil(PUBLIC_SINGLETON_TEST.dsm)
+ assert_nil(PUBLIC_SINGLETON_TEST.def)
+ end
+
+ def test_define_singleton_method_no_proc
+ o = Object.new
+ assert_raise(ArgumentError) {
+ o.instance_eval { define_singleton_method(:bar) }
+ }
+
+ bug11283 = '[ruby-core:69655] [Bug #11283]'
+ def o.define(n)
+ define_singleton_method(n)
+ end
+ assert_raise(ArgumentError, bug11283) {o.define(:bar) {:bar}}
+ end
+
+ def test_define_method_invalid_arg
assert_raise(TypeError) do
Class.new.class_eval { define_method(:foo, Object.new) }
end
@@ -227,12 +376,97 @@ class TestMethod < Test::Unit::TestCase
assert_raise(TypeError) do
Module.new.module_eval {define_method(:foo, Base.instance_method(:foo))}
end
+ end
- assert_raise(TypeError) do
- Class.new.class_eval {define_method(:meth, M.instance_method(:meth))}
+ def test_define_singleton_method_with_extended_method
+ bug8686 = "[ruby-core:56174]"
+
+ m = Module.new do
+ extend self
+
+ def a
+ "a"
+ end
+ end
+
+ assert_nothing_raised(bug8686) do
+ m.define_singleton_method(:a, m.method(:a))
+ end
+ end
+
+ def test_define_method_transplating
+ feature4254 = '[ruby-core:34267]'
+ m = Module.new {define_method(:meth, M.instance_method(:meth))}
+ assert_equal(:meth, Object.new.extend(m).meth, feature4254)
+ c = Class.new {define_method(:meth, M.instance_method(:meth))}
+ assert_equal(:meth, c.new.meth, feature4254)
+ end
+
+ def test_define_method_visibility
+ c = Class.new do
+ public
+ define_method(:foo) {:foo}
+ protected
+ define_method(:bar) {:bar}
+ private
+ define_method(:baz) {:baz}
+ end
+
+ assert_equal(true, c.public_method_defined?(:foo))
+ assert_equal(false, c.public_method_defined?(:bar))
+ assert_equal(false, c.public_method_defined?(:baz))
+
+ assert_equal(false, c.protected_method_defined?(:foo))
+ assert_equal(true, c.protected_method_defined?(:bar))
+ assert_equal(false, c.protected_method_defined?(:baz))
+
+ assert_equal(false, c.private_method_defined?(:foo))
+ assert_equal(false, c.private_method_defined?(:bar))
+ assert_equal(true, c.private_method_defined?(:baz))
+
+ m = Module.new do
+ module_function
+ define_method(:foo) {:foo}
+ end
+ assert_equal(true, m.respond_to?(:foo))
+ assert_equal(false, m.public_method_defined?(:foo))
+ assert_equal(false, m.protected_method_defined?(:foo))
+ assert_equal(true, m.private_method_defined?(:foo))
+ end
+
+ def test_define_method_in_private_scope
+ bug9005 = '[ruby-core:57747] [Bug #9005]'
+ c = Class.new
+ class << c
+ public :define_method
+ end
+ TOPLEVEL_BINDING.eval("proc{|c|c.define_method(:x) {|x|throw x}}").call(c)
+ o = c.new
+ assert_throw(bug9005) {o.x(bug9005)}
+ end
+
+ def test_singleton_define_method_in_private_scope
+ bug9141 = '[ruby-core:58497] [Bug #9141]'
+ o = Object.new
+ class << o
+ public :define_singleton_method
+ end
+ TOPLEVEL_BINDING.eval("proc{|o|o.define_singleton_method(:x) {|x|throw x}}").call(o)
+ assert_throw(bug9141) do
+ o.x(bug9141)
end
end
+ def test_super_in_proc_from_define_method
+ c1 = Class.new {
+ def m
+ :m1
+ end
+ }
+ c2 = Class.new(c1) { define_method(:m) { Proc.new { super() } } }
+ assert_equal(:m1, c2.new.m.call, 'see [Bug #4881] and [Bug #3136]')
+ end
+
def test_clone
o = Object.new
def o.foo; :foo; end
@@ -242,34 +476,60 @@ class TestMethod < Test::Unit::TestCase
assert_equal(:bar, m.clone.bar)
end
- def test_call
- o = Object.new
- def o.foo; p 1; end
- def o.bar(x); x; end
- m = o.method(:foo)
- m.taint
- assert_raise(SecurityError) { m.call }
+ def test_clone_under_gc_compact_stress
+ omit "compaction doesn't work well on s390x" if RUBY_PLATFORM =~ /s390x/ # https://github.com/ruby/ruby/pull/5077
+ EnvUtil.under_gc_compact_stress do
+ o = Object.new
+ def o.foo; :foo; end
+ m = o.method(:foo)
+ def m.bar; :bar; end
+ assert_equal(:foo, m.clone.call)
+ assert_equal(:bar, m.clone.bar)
+ end
end
def test_inspect
o = Object.new
- def o.foo; end
+ def o.foo; end; line_no = __LINE__
m = o.method(:foo)
- assert_equal("#<Method: #{ o.inspect }.foo>", m.inspect)
+ assert_equal("#<Method: #{ o.inspect }.foo() #{__FILE__}:#{line_no}>", m.inspect)
m = o.method(:foo)
- assert_equal("#<UnboundMethod: #{ class << o; self; end.inspect }#foo>", m.unbind.inspect)
+ assert_match("#<UnboundMethod: #{ class << o; self; end.inspect }#foo() #{__FILE__}:#{line_no}", m.unbind.inspect)
c = Class.new
- c.class_eval { def foo; end; }
+ c.class_eval { def foo; end; }; line_no = __LINE__
m = c.new.method(:foo)
- assert_equal("#<Method: #{ c.inspect }#foo>", m.inspect)
+ assert_equal("#<Method: #{ c.inspect }#foo() #{__FILE__}:#{line_no}>", m.inspect)
m = c.instance_method(:foo)
- assert_equal("#<UnboundMethod: #{ c.inspect }#foo>", m.inspect)
+ assert_equal("#<UnboundMethod: #{ c.inspect }#foo() #{__FILE__}:#{line_no}>", m.inspect)
c2 = Class.new(c)
c2.class_eval { private :foo }
m2 = c2.new.method(:foo)
- assert_equal("#<Method: #{ c2.inspect }(#{ c.inspect })#foo>", m2.inspect)
+ assert_equal("#<Method: #{ c2.inspect }(#{ c.inspect })#foo() #{__FILE__}:#{line_no}>", m2.inspect)
+
+ bug7806 = '[ruby-core:52048] [Bug #7806]'
+ c3 = Class.new(c)
+ c3.class_eval { alias bar foo }
+ m3 = c3.new.method(:bar)
+ assert_equal("#<Method: #{c3.inspect}(#{c.inspect})#bar(foo)() #{__FILE__}:#{line_no}>", m3.inspect, bug7806)
+
+ bug15608 = '[ruby-core:91570] [Bug #15608]'
+ c4 = Class.new(c)
+ c4.class_eval { alias bar foo }
+ o = c4.new
+ o.singleton_class
+ m4 = o.method(:bar)
+ assert_equal("#<Method: #{c4.inspect}(#{c.inspect})#bar(foo)() #{__FILE__}:#{line_no}>", m4.inspect, bug15608)
+
+ bug17428 = '[ruby-core:101635] [Bug #17428]'
+ assert_equal("#<Method: #<Class:String>(Module)#prepend(*)>", String.method(:prepend).inspect, bug17428)
+
+ c5 = Class.new(String)
+ m = Module.new{def prepend; end; alias prep prepend}; line_no = __LINE__
+ c5.extend(m)
+ c6 = Class.new(c5)
+ assert_equal("#<Method: #<Class:#{c6.inspect}>(#{m.inspect})#prep(prepend)() #{__FILE__}:#{line_no}>", c6.method(:prep).inspect, bug17428)
end
def test_callee_top_level
@@ -295,10 +555,32 @@ class TestMethod < Test::Unit::TestCase
end
def test_default_accessibility
- assert T.public_instance_methods.include?(:normal_method), 'normal methods are public by default'
- assert !T.public_instance_methods.include?(:initialize), '#initialize is private'
- assert !M.public_instance_methods.include?(:func), 'module methods are private by default'
- assert M.public_instance_methods.include?(:meth), 'normal methods are public by default'
+ tmethods = T.public_instance_methods
+ assert_include tmethods, :normal_method, 'normal methods are public by default'
+ assert_not_include tmethods, :initialize, '#initialize is private'
+ assert_not_include tmethods, :initialize_copy, '#initialize_copy is private'
+ assert_not_include tmethods, :initialize_clone, '#initialize_clone is private'
+ assert_not_include tmethods, :initialize_dup, '#initialize_dup is private'
+ assert_not_include tmethods, :respond_to_missing?, '#respond_to_missing? is private'
+ mmethods = M.public_instance_methods
+ assert_not_include mmethods, :func, 'module methods are private by default'
+ assert_include mmethods, :meth, 'normal methods are public by default'
+ end
+
+ def test_respond_to_missing_argument
+ obj = Struct.new(:mid).new
+ def obj.respond_to_missing?(id, *)
+ self.mid = id
+ true
+ end
+ assert_kind_of(Method, obj.method("bug15640"))
+ assert_kind_of(Symbol, obj.mid)
+ assert_equal("bug15640", obj.mid.to_s)
+
+ arg = Struct.new(:to_str).new("bug15640_2")
+ assert_kind_of(Method, obj.method(arg))
+ assert_kind_of(Symbol, obj.mid)
+ assert_equal("bug15640_2", obj.mid.to_s)
end
define_method(:pm0) {||}
@@ -311,7 +593,16 @@ class TestMethod < Test::Unit::TestCase
define_method(:pmo5) {|a, *b, c|}
define_method(:pmo6) {|a, *b, c, &d|}
define_method(:pmo7) {|a, b = nil, *c, d, &e|}
- define_method(:pma1) {|(a), &b|}
+ define_method(:pma1) {|(a), &b| nil && a}
+ define_method(:pmk1) {|**|}
+ define_method(:pmk2) {|**o|}
+ define_method(:pmk3) {|a, **o|}
+ define_method(:pmk4) {|a = nil, **o|}
+ define_method(:pmk5) {|a, b = nil, **o|}
+ define_method(:pmk6) {|a, b = nil, c, **o|}
+ define_method(:pmk7) {|a, b = nil, *c, d, **o|}
+ define_method(:pmk8) {|a, b = nil, *c, d, e:, f: nil, **o|}
+ define_method(:pmnk) {|**nil|}
def test_bound_parameters
assert_equal([], method(:m0).parameters)
@@ -324,7 +615,19 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:mo5).parameters)
assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:mo6).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:mo7).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :*], [:req, :d], [:block, :e]], method(:mo8).parameters)
assert_equal([[:req], [:block, :b]], method(:ma1).parameters)
+ assert_equal([[:keyrest, :**]], method(:mk1).parameters)
+ assert_equal([[:keyrest, :o]], method(:mk2).parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], method(:mk3).parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], method(:mk4).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], method(:mk5).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], method(:mk6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:mk7).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], method(:mk8).parameters)
+ assert_equal([[:nokey]], method(:mnk).parameters)
+ # pending
+ assert_equal([[:rest, :*], [:keyrest, :**], [:block, :&]], method(:mf).parameters)
end
def test_unbound_parameters
@@ -338,7 +641,19 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:mo5).parameters)
assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:mo6).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:mo7).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :*], [:req, :d], [:block, :e]], self.class.instance_method(:mo8).parameters)
assert_equal([[:req], [:block, :b]], self.class.instance_method(:ma1).parameters)
+ assert_equal([[:keyrest, :**]], self.class.instance_method(:mk1).parameters)
+ assert_equal([[:keyrest, :o]], self.class.instance_method(:mk2).parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], self.class.instance_method(:mk3).parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], self.class.instance_method(:mk4).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], self.class.instance_method(:mk5).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], self.class.instance_method(:mk6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:mk7).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], self.class.instance_method(:mk8).parameters)
+ assert_equal([[:nokey]], self.class.instance_method(:mnk).parameters)
+ # pending
+ assert_equal([[:rest, :*], [:keyrest, :**], [:block, :&]], self.class.instance_method(:mf).parameters)
end
def test_bmethod_bound_parameters
@@ -353,6 +668,15 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).parameters)
assert_equal([[:req], [:block, :b]], method(:pma1).parameters)
+ assert_equal([[:keyrest, :**]], method(:pmk1).parameters)
+ assert_equal([[:keyrest, :o]], method(:pmk2).parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], method(:pmk3).parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], method(:pmk4).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], method(:pmk5).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], method(:pmk6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:pmk7).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], method(:pmk8).parameters)
+ assert_equal([[:nokey]], method(:pmnk).parameters)
end
def test_bmethod_unbound_parameters
@@ -367,6 +691,71 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:pmo6).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:pmo7).parameters)
assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters)
+ assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters)
+ assert_equal([[:keyrest, :**]], self.class.instance_method(:pmk1).parameters)
+ assert_equal([[:keyrest, :o]], self.class.instance_method(:pmk2).parameters)
+ assert_equal([[:req, :a], [:keyrest, :o]], self.class.instance_method(:pmk3).parameters)
+ assert_equal([[:opt, :a], [:keyrest, :o]], self.class.instance_method(:pmk4).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:keyrest, :o]], self.class.instance_method(:pmk5).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:req, :c], [:keyrest, :o]], self.class.instance_method(:pmk6).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:pmk7).parameters)
+ assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], self.class.instance_method(:pmk8).parameters)
+ assert_equal([[:nokey]], self.class.instance_method(:pmnk).parameters)
+ end
+
+ def test_hidden_parameters
+ instance_eval("def m((_)"+",(_)"*256+");end")
+ assert_empty(method(:m).parameters.map{|_,n|n}.compact)
+ end
+
+ def test_method_parameters_inspect
+ assert_include(method(:m0).inspect, "()")
+ assert_include(method(:m1).inspect, "(a)")
+ assert_include(method(:m2).inspect, "(a, b)")
+ assert_include(method(:mo1).inspect, "(a=..., &b)")
+ assert_include(method(:mo2).inspect, "(a, b=...)")
+ assert_include(method(:mo3).inspect, "(*a)")
+ assert_include(method(:mo4).inspect, "(a, *b, &c)")
+ assert_include(method(:mo5).inspect, "(a, *b, c)")
+ assert_include(method(:mo6).inspect, "(a, *b, c, &d)")
+ assert_include(method(:mo7).inspect, "(a, b=..., *c, d, &e)")
+ assert_include(method(:mo8).inspect, "(a, b=..., *, d, &e)")
+ assert_include(method(:ma1).inspect, "(_, &b)")
+ assert_include(method(:mk1).inspect, "(**)")
+ assert_include(method(:mk2).inspect, "(**o)")
+ assert_include(method(:mk3).inspect, "(a, **o)")
+ assert_include(method(:mk4).inspect, "(a=..., **o)")
+ assert_include(method(:mk5).inspect, "(a, b=..., **o)")
+ assert_include(method(:mk6).inspect, "(a, b=..., c, **o)")
+ assert_include(method(:mk7).inspect, "(a, b=..., *c, d, **o)")
+ assert_include(method(:mk8).inspect, "(a, b=..., *c, d, e:, f: ..., **o)")
+ assert_include(method(:mnk).inspect, "(**nil)")
+ assert_include(method(:mf).inspect, "(...)")
+ end
+
+ def test_unbound_method_parameters_inspect
+ assert_include(self.class.instance_method(:m0).inspect, "()")
+ assert_include(self.class.instance_method(:m1).inspect, "(a)")
+ assert_include(self.class.instance_method(:m2).inspect, "(a, b)")
+ assert_include(self.class.instance_method(:mo1).inspect, "(a=..., &b)")
+ assert_include(self.class.instance_method(:mo2).inspect, "(a, b=...)")
+ assert_include(self.class.instance_method(:mo3).inspect, "(*a)")
+ assert_include(self.class.instance_method(:mo4).inspect, "(a, *b, &c)")
+ assert_include(self.class.instance_method(:mo5).inspect, "(a, *b, c)")
+ assert_include(self.class.instance_method(:mo6).inspect, "(a, *b, c, &d)")
+ assert_include(self.class.instance_method(:mo7).inspect, "(a, b=..., *c, d, &e)")
+ assert_include(self.class.instance_method(:mo8).inspect, "(a, b=..., *, d, &e)")
+ assert_include(self.class.instance_method(:ma1).inspect, "(_, &b)")
+ assert_include(self.class.instance_method(:mk1).inspect, "(**)")
+ assert_include(self.class.instance_method(:mk2).inspect, "(**o)")
+ assert_include(self.class.instance_method(:mk3).inspect, "(a, **o)")
+ assert_include(self.class.instance_method(:mk4).inspect, "(a=..., **o)")
+ assert_include(self.class.instance_method(:mk5).inspect, "(a, b=..., **o)")
+ assert_include(self.class.instance_method(:mk6).inspect, "(a, b=..., c, **o)")
+ assert_include(self.class.instance_method(:mk7).inspect, "(a, b=..., *c, d, **o)")
+ assert_include(self.class.instance_method(:mk8).inspect, "(a, b=..., *c, d, e:, f: ..., **o)")
+ assert_include(self.class.instance_method(:mnk).inspect, "(**nil)")
+ assert_include(self.class.instance_method(:mf).inspect, "(...)")
end
def test_public_method_with_zsuper_method
@@ -405,7 +794,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal(true, respond_to?(:mv1))
assert_equal(false, respond_to?(:mv2))
- assert_equal(true, respond_to?(:mv3))
+ assert_equal(false, respond_to?(:mv3))
assert_equal(true, respond_to?(:mv1, true))
assert_equal(true, respond_to?(:mv2, true))
@@ -416,9 +805,18 @@ class TestMethod < Test::Unit::TestCase
assert_nothing_raised { mv3 }
assert_nothing_raised { self.mv1 }
- assert_raise(NoMethodError) { self.mv2 }
+ assert_nothing_raised { self.mv2 }
+ assert_raise(NoMethodError) { (self).mv2 }
assert_nothing_raised { self.mv3 }
+ class << (obj = Object.new)
+ private def [](x) x end
+ def mv1(x) self[x] end
+ def mv2(x) (self)[x] end
+ end
+ assert_nothing_raised { obj.mv1(0) }
+ assert_raise(NoMethodError) { obj.mv2(0) }
+
v = Visibility.new
assert_equal('method', defined?(v.mv1))
@@ -427,7 +825,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal(true, v.respond_to?(:mv1))
assert_equal(false, v.respond_to?(:mv2))
- assert_equal(true, v.respond_to?(:mv3))
+ assert_equal(false, v.respond_to?(:mv3))
assert_equal(true, v.respond_to?(:mv1, true))
assert_equal(true, v.respond_to?(:mv2, true))
@@ -445,4 +843,1051 @@ class TestMethod < Test::Unit::TestCase
assert_nothing_raised { v.instance_eval { mv2 } }
assert_nothing_raised { v.instance_eval { mv3 } }
end
+
+ def test_bound_method_entry
+ bug6171 = '[ruby-core:43383]'
+ assert_ruby_status([], <<-EOC, bug6171)
+ class Bug6171
+ def initialize(target)
+ define_singleton_method(:reverse, target.method(:reverse).to_proc)
+ end
+ end
+ 100.times {p = Bug6171.new('test'); 1000.times {p.reverse}}
+ EOC
+ end
+
+ def test_unbound_method_proc_coerce
+ # '&' coercion of an UnboundMethod raises TypeError
+ assert_raise(TypeError) do
+ Class.new do
+ define_method('foo', &Object.instance_method(:to_s))
+ end
+ end
+ end
+
+ def test___dir__
+ assert_instance_of String, __dir__
+ assert_equal(File.dirname(File.realpath(__FILE__)), __dir__)
+ bug8436 = '[ruby-core:55123] [Bug #8436]'
+ file, line = *binding.source_location
+ file = File.realpath(file)
+ assert_equal(__dir__, eval("__dir__", binding, file, line), bug8436)
+ bug8662 = '[ruby-core:56099] [Bug #8662]'
+ assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662)
+ assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662)
+ end
+
+ def test_alias_owner
+ bug7613 = '[ruby-core:51105]'
+ bug7993 = '[Bug #7993]'
+ c = Class.new {
+ def foo
+ end
+ prepend Module.new
+ attr_reader :zot
+ }
+ x = c.new
+ class << x
+ alias bar foo
+ end
+ assert_equal(c, c.instance_method(:foo).owner)
+ assert_equal(c, x.method(:foo).owner)
+ assert_equal(x.singleton_class, x.method(:bar).owner)
+ assert_equal(x.method(:foo), x.method(:bar), bug7613)
+ assert_equal(c, x.method(:zot).owner, bug7993)
+ assert_equal(c, c.instance_method(:zot).owner, bug7993)
+ end
+
+ def test_included
+ m = Module.new {
+ def foo
+ end
+ }
+ c = Class.new {
+ def foo
+ end
+ include m
+ }
+ assert_equal(c, c.instance_method(:foo).owner)
+ end
+
+ def test_prepended
+ bug7836 = '[ruby-core:52160] [Bug #7836]'
+ bug7988 = '[ruby-core:53038] [Bug #7988]'
+ m = Module.new {
+ def foo
+ end
+ }
+ c = Class.new {
+ def foo
+ end
+ prepend m
+ }
+ assert_raise(NameError, bug7988) {Module.new{prepend m}.instance_method(:bar)}
+ true || c || bug7836
+ end
+
+ def test_gced_bmethod
+ assert_normal_exit %q{
+ require 'irb'
+ IRB::Irb.module_eval do
+ define_method(:eval_input) do
+ IRB::Irb.module_eval { alias_method :eval_input, :to_s }
+ GC.start
+ Kernel
+ end
+ end
+ IRB.start
+ }, '[Bug #7825]'
+ end
+
+ def test_singleton_method
+ feature8391 = '[ruby-core:54914] [Feature #8391]'
+ c1 = Class.new
+ c1.class_eval { def foo; :foo; end }
+ o = c1.new
+ def o.bar; :bar; end
+ assert_nothing_raised(NameError) {o.method(:foo)}
+ assert_raise(NameError, feature8391) {o.singleton_method(:foo)}
+ m = assert_nothing_raised(NameError, feature8391) {break o.singleton_method(:bar)}
+ assert_equal(:bar, m.call, feature8391)
+ end
+
+ def test_singleton_method_prepend
+ bug14658 = '[Bug #14658]'
+ c1 = Class.new
+ o = c1.new
+ def o.bar; :bar; end
+ class << o; prepend Module.new; end
+ m = assert_nothing_raised(NameError, bug14658) {o.singleton_method(:bar)}
+ assert_equal(:bar, m.call, bug14658)
+
+ o = Object.new
+ assert_raise(NameError, bug14658) {o.singleton_method(:bar)}
+ end
+
+ def test_singleton_method_included_or_prepended_bug_20620
+ m = Module.new do
+ extend self
+ def foo = :foo
+ end
+ assert_equal(:foo, m.singleton_method(:foo).call)
+ assert_raise(NameError) {m.singleton_method(:puts)}
+
+ sc = Class.new do
+ def t = :t
+ end
+ c = Class.new(sc) do
+ singleton_class.prepend(Module.new do
+ def bar = :bar
+ end)
+ extend(Module.new do
+ def quux = :quux
+ end)
+ def self.baz = :baz
+ end
+ assert_equal(:bar, c.singleton_method(:bar).call)
+ assert_equal(:baz, c.singleton_method(:baz).call)
+ assert_equal(:quux, c.singleton_method(:quux).call)
+
+ assert_raise(NameError) {c.singleton_method(:t)}
+
+ c2 = Class.new(c)
+ assert_raise(NameError) {c2.singleton_method(:bar)}
+ assert_raise(NameError) {c2.singleton_method(:baz)}
+ assert_raise(NameError) {c2.singleton_method(:quux)}
+ end
+
+ Feature9783 = '[ruby-core:62212] [Feature #9783]'
+
+ def assert_curry_three_args(m)
+ curried = m.curry
+ assert_equal(6, curried.(1).(2).(3), Feature9783)
+
+ curried = m.curry(3)
+ assert_equal(6, curried.(1).(2).(3), Feature9783)
+
+ assert_raise_with_message(ArgumentError, /wrong number/) {m.curry(2)}
+ end
+
+ def test_curry_method
+ c = Class.new {
+ def three_args(a,b,c) a + b + c end
+ }
+ assert_curry_three_args(c.new.method(:three_args))
+ end
+
+ def test_curry_from_proc
+ c = Class.new {
+ define_method(:three_args) {|x,y,z| x + y + z}
+ }
+ assert_curry_three_args(c.new.method(:three_args))
+ end
+
+ def assert_curry_var_args(m)
+ curried = m.curry(3)
+ assert_equal([1, 2, 3], curried.(1).(2).(3), Feature9783)
+
+ curried = m.curry(2)
+ assert_equal([1, 2], curried.(1).(2), Feature9783)
+
+ curried = m.curry(0)
+ assert_equal([1], curried.(1), Feature9783)
+ end
+
+ def test_curry_var_args
+ c = Class.new {
+ def var_args(*args) args end
+ }
+ assert_curry_var_args(c.new.method(:var_args))
+ end
+
+ def test_curry_from_proc_var_args
+ c = Class.new {
+ define_method(:var_args) {|*args| args}
+ }
+ assert_curry_var_args(c.new.method(:var_args))
+ end
+
+ Feature9781 = '[ruby-core:62202] [Feature #9781]'
+
+ def test_super_method
+ o = Derived.new
+ m = o.method(:foo).super_method
+ assert_equal(Base, m.owner, Feature9781)
+ assert_same(o, m.receiver, Feature9781)
+ assert_equal(:foo, m.name, Feature9781)
+ m = assert_nothing_raised(NameError, Feature9781) {break m.super_method}
+ assert_nil(m, Feature9781)
+ end
+
+ def test_super_method_unbound
+ m = Derived.instance_method(:foo)
+ m = m.super_method
+ assert_equal(Base.instance_method(:foo), m, Feature9781)
+ m = assert_nothing_raised(NameError, Feature9781) {break m.super_method}
+ assert_nil(m, Feature9781)
+
+ bug11419 = '[ruby-core:70254]'
+ m = Object.instance_method(:tap)
+ m = assert_nothing_raised(NameError, bug11419) {break m.super_method}
+ assert_nil(m, bug11419)
+ end
+
+ def test_super_method_module
+ m1 = Module.new {def foo; end}
+ c1 = Class.new(Derived) {include m1; def foo; end}
+ m = c1.instance_method(:foo)
+ assert_equal(c1, m.owner, Feature9781)
+ m = m.super_method
+ assert_equal(m1, m.owner, Feature9781)
+ m = m.super_method
+ assert_equal(Derived, m.owner, Feature9781)
+ m = m.super_method
+ assert_equal(Base, m.owner, Feature9781)
+ m2 = Module.new {def foo; end}
+ o = c1.new.extend(m2)
+ m = o.method(:foo)
+ assert_equal(m2, m.owner, Feature9781)
+ m = m.super_method
+ assert_equal(c1, m.owner, Feature9781)
+ assert_same(o, m.receiver, Feature9781)
+
+ c1 = Class.new {def foo; end}
+ c2 = Class.new(c1) {include m1; include m2}
+ m = c2.instance_method(:foo)
+ assert_equal(m2, m.owner)
+ m = m.super_method
+ assert_equal(m1, m.owner)
+ m = m.super_method
+ assert_equal(c1, m.owner)
+ assert_nil(m.super_method)
+ end
+
+ def test_super_method_bind_unbind_clone
+ bug15629_m1 = Module.new do
+ def foo; end
+ end
+
+ bug15629_m2 = Module.new do
+ def foo; end
+ end
+
+ bug15629_c = Class.new do
+ include bug15629_m1
+ include bug15629_m2
+ end
+
+ o = bug15629_c.new
+ m = o.method(:foo)
+ sm = m.super_method
+ im = bug15629_c.instance_method(:foo)
+ sim = im.super_method
+
+ assert_equal(sm, m.clone.super_method)
+ assert_equal(sim, m.unbind.super_method)
+ assert_equal(sim, m.unbind.clone.super_method)
+ assert_equal(sim, im.clone.super_method)
+ assert_equal(sm, m.unbind.bind(o).super_method)
+ assert_equal(sm, m.unbind.clone.bind(o).super_method)
+ assert_equal(sm, im.bind(o).super_method)
+ assert_equal(sm, im.clone.bind(o).super_method)
+ end
+
+ def test_super_method_removed_public
+ c1 = Class.new {private def foo; end}
+ c2 = Class.new(c1) {public :foo}
+ c3 = Class.new(c2) {def foo; end}
+ c1.class_eval {undef foo}
+ m = c3.instance_method(:foo)
+ m = assert_nothing_raised(NameError, Feature9781) {break m.super_method}
+ assert_nil(m, Feature9781)
+ end
+
+ def test_super_method_removed_regular
+ c1 = Class.new { def foo; end }
+ c2 = Class.new(c1) { def foo; end }
+ assert_equal c1.instance_method(:foo), c2.instance_method(:foo).super_method
+ c1.remove_method :foo
+ assert_equal nil, c2.instance_method(:foo).super_method
+ end
+
+ def test_prepended_public_zsuper
+ mod = EnvUtil.labeled_module("Mod") {private def foo; [:ok] end}
+ obj = Object.new.extend(mod)
+
+ class << obj
+ public :foo
+ end
+
+ mod1 = EnvUtil.labeled_module("Mod1") {def foo; [:mod1] + super end}
+ obj.singleton_class.prepend(mod1)
+
+ mod2 = EnvUtil.labeled_module("Mod2") {def foo; [:mod2] + super end}
+ obj.singleton_class.prepend(mod2)
+
+ m = obj.method(:foo)
+ assert_equal mod2, m.owner
+ assert_equal mod1, m.super_method.owner
+ assert_equal obj.singleton_class, m.super_method.super_method.owner
+ assert_equal nil, m.super_method.super_method.super_method
+
+ assert_equal [:mod2, :mod1, :ok], obj.foo
+ end
+
+ def test_super_method_with_prepended_module
+ bug = '[ruby-core:81666] [Bug #13656] should be the method of the parent'
+ c1 = EnvUtil.labeled_class("C1") {def m; end}
+ c2 = EnvUtil.labeled_class("C2", c1) {def m; end}
+ c2.prepend(EnvUtil.labeled_module("M"))
+ m1 = c1.instance_method(:m)
+ m2 = c2.instance_method(:m).super_method
+ assert_equal(m1, m2, bug)
+ assert_equal(c1, m2.owner, bug)
+ assert_equal(m1.source_location, m2.source_location, bug)
+ end
+
+ def test_super_method_after_bind
+ assert_nil String.instance_method(:length).bind(String.new).super_method,
+ '[ruby-core:85231] [Bug #14421]'
+ end
+
+ def test_super_method_alias
+ c0 = Class.new do
+ def m1
+ [:C0_m1]
+ end
+ def m2
+ [:C0_m2]
+ end
+ end
+
+ c1 = Class.new(c0) do
+ def m1
+ [:C1_m1] + super
+ end
+ alias m2 m1
+ end
+
+ c2 = Class.new(c1) do
+ def m2
+ [:C2_m2] + super
+ end
+ end
+ o1 = c2.new
+ assert_equal([:C2_m2, :C1_m1, :C0_m1], o1.m2)
+
+ m = o1.method(:m2)
+ assert_equal([:C2_m2, :C1_m1, :C0_m1], m.call)
+
+ m = m.super_method
+ assert_equal([:C1_m1, :C0_m1], m.call)
+
+ m = m.super_method
+ assert_equal([:C0_m1], m.call)
+
+ assert_nil(m.super_method)
+ end
+
+ def test_super_method_alias_to_prepended_module
+ m = Module.new do
+ def m1
+ [:P_m1] + super
+ end
+
+ def m2
+ [:P_m2] + super
+ end
+ end
+
+ c0 = Class.new do
+ def m1
+ [:C0_m1]
+ end
+ end
+
+ c1 = Class.new(c0) do
+ def m1
+ [:C1_m1] + super
+ end
+ prepend m
+ alias m2 m1
+ end
+
+ o1 = c1.new
+ assert_equal([:P_m2, :P_m1, :C1_m1, :C0_m1], o1.m2)
+
+ m = o1.method(:m2)
+ assert_equal([:P_m2, :P_m1, :C1_m1, :C0_m1], m.call)
+
+ m = m.super_method
+ assert_equal([:P_m1, :C1_m1, :C0_m1], m.call)
+
+ m = m.super_method
+ assert_equal([:C1_m1, :C0_m1], m.call)
+
+ m = m.super_method
+ assert_equal([:C0_m1], m.call)
+
+ assert_nil(m.super_method)
+ end
+
+ # Bug 17780
+ def test_super_method_module_alias
+ m = Module.new do
+ def foo
+ end
+ alias :f :foo
+ end
+
+ method = m.instance_method(:f)
+ super_method = method.super_method
+ assert_nil(super_method)
+ end
+
+ # Bug 18435
+ def test_instance_methods_owner_consistency
+ a = Module.new { def method1; end }
+
+ b = Class.new do
+ include a
+ protected :method1
+ end
+
+ assert_equal [:method1], b.instance_methods(false)
+ assert_equal b, b.instance_method(:method1).owner
+ end
+
+ def test_zsuper_method_removed
+ a = EnvUtil.labeled_class('A') do
+ private
+ def foo(arg = nil)
+ 1
+ end
+ end
+ line = __LINE__ - 4
+
+ b = EnvUtil.labeled_class('B', a) do
+ public :foo
+ end
+
+ unbound = b.instance_method(:foo)
+
+ assert_equal unbound, b.public_instance_method(:foo)
+ assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
+ assert_equal [[:opt, :arg]], unbound.parameters
+
+ a.remove_method(:foo)
+
+ assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
+ assert_equal [[:opt, :arg]], unbound.parameters
+
+ obj = b.new
+ assert_equal 1, unbound.bind_call(obj)
+
+ assert_include b.instance_methods(false), :foo
+ link = 'https://github.com/ruby/ruby/pull/6467#issuecomment-1262159088'
+ assert_raise(NameError, link) { b.instance_method(:foo) }
+ # For #test_method_list below, otherwise we get the same error as just above
+ b.remove_method(:foo)
+ end
+
+ def test_zsuper_method_removed_higher_method
+ a0 = EnvUtil.labeled_class('A0') do
+ def foo(arg1 = nil, arg2 = nil)
+ 0
+ end
+ end
+ line0 = __LINE__ - 4
+ a0_foo = a0.instance_method(:foo)
+
+ a = EnvUtil.labeled_class('A', a0) do
+ private
+ def foo(arg = nil)
+ 1
+ end
+ end
+ line = __LINE__ - 4
+
+ b = EnvUtil.labeled_class('B', a) do
+ public :foo
+ end
+
+ unbound = b.instance_method(:foo)
+
+ assert_equal a0_foo, unbound.super_method
+
+ a.remove_method(:foo)
+
+ assert_equal "#<UnboundMethod: A#foo(arg=...) #{__FILE__}:#{line}>", unbound.inspect
+ assert_equal [[:opt, :arg]], unbound.parameters
+ assert_equal a0_foo, unbound.super_method
+
+ obj = b.new
+ assert_equal 1, unbound.bind_call(obj)
+
+ assert_include b.instance_methods(false), :foo
+ assert_equal "#<UnboundMethod: A0#foo(arg1=..., arg2=...) #{__FILE__}:#{line0}>", b.instance_method(:foo).inspect
+ end
+
+ def test_zsuper_method_redefined_bind_call
+ c0 = EnvUtil.labeled_class('C0') do
+ def foo
+ [:foo]
+ end
+ end
+
+ c1 = EnvUtil.labeled_class('C1', c0) do
+ def foo
+ super + [:bar]
+ end
+ end
+ m1 = c1.instance_method(:foo)
+
+ c2 = EnvUtil.labeled_class('C2', c1) do
+ private :foo
+ end
+
+ assert_equal [:foo], c2.private_instance_methods(false)
+ m2 = c2.instance_method(:foo)
+
+ c1.class_exec do
+ remove_method :foo
+ def foo
+ [:bar2]
+ end
+ end
+
+ m3 = c2.instance_method(:foo)
+ c = c2.new
+ assert_equal [:foo, :bar], m1.bind_call(c)
+ assert_equal c1, m1.owner
+ assert_equal [:foo, :bar], m2.bind_call(c)
+ assert_equal c2, m2.owner
+ assert_equal [:bar2], m3.bind_call(c)
+ assert_equal c2, m3.owner
+ end
+
+ # Bug #18751
+ def method_equality_visbility_alias
+ c = Class.new do
+ class << self
+ alias_method :n, :new
+ private :new
+ end
+ end
+
+ assert_equal c.method(:n), c.method(:new)
+
+ assert_not_equal c.method(:n), Class.method(:new)
+ assert_equal c.method(:n) == Class.instance_method(:new).bind(c)
+
+ assert_not_equal c.method(:new), Class.method(:new)
+ assert_equal c.method(:new), Class.instance_method(:new).bind(c)
+ end
+
+ def rest_parameter(*rest)
+ rest
+ end
+
+ def test_splat_long_array
+ if File.exist?('/etc/os-release') && File.read('/etc/os-release').include?('openSUSE Leap')
+ # For RubyCI's openSUSE machine http://rubyci.s3.amazonaws.com/opensuseleap/ruby-trunk/recent.html, which tends to die with NoMemoryError here.
+ omit 'do not exhaust memory on RubyCI openSUSE Leap machine'
+ end
+ n = 10_000_000
+ assert_equal n , rest_parameter(*(1..n)).size, '[Feature #10440]'
+ end
+
+ class C
+ D = "Const_D"
+ def foo
+ a = b = c = a = b = c = 12345
+ end
+
+ def binding_noarg
+ a = a = 12345
+ binding
+ end
+
+ def binding_one_arg(x)
+ a = a = 12345
+ binding
+ end
+
+ def binding_optargs(x, y=42)
+ a = a = 12345
+ binding
+ end
+
+ def binding_anyargs(*x)
+ a = a = 12345
+ binding
+ end
+
+ def binding_keywords(x: 42)
+ a = a = 12345
+ binding
+ end
+
+ def binding_anykeywords(**x)
+ a = a = 12345
+ binding
+ end
+
+ def binding_forwarding(...)
+ a = a = 12345
+ binding
+ end
+
+ def binding_forwarding1(x, ...)
+ a = a = 12345
+ binding
+ end
+ end
+
+ def test_to_proc_binding
+ bug11012 = '[ruby-core:68673] [Bug #11012]'
+
+ b = C.new.method(:foo).to_proc.binding
+ assert_equal([], b.local_variables, bug11012)
+ assert_equal("Const_D", b.eval("D"), bug11012) # Check CREF
+
+ assert_raise(NameError, bug11012){ b.local_variable_get(:foo) }
+ assert_equal(123, b.local_variable_set(:foo, 123), bug11012)
+ assert_equal(123, b.local_variable_get(:foo), bug11012)
+ assert_equal(456, b.local_variable_set(:bar, 456), bug11012)
+ assert_equal(123, b.local_variable_get(:foo), bug11012)
+ assert_equal(456, b.local_variable_get(:bar), bug11012)
+ assert_equal([:bar, :foo], b.local_variables.sort, bug11012)
+ end
+
+ def test_method_binding
+ c = C.new
+
+ b = c.binding_noarg
+ assert_equal(12345, b.local_variable_get(:a))
+
+ b = c.binding_one_arg(0)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal(0, b.local_variable_get(:x))
+
+ b = c.binding_anyargs()
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal([], b.local_variable_get(:x))
+ b = c.binding_anyargs(0)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal([0], b.local_variable_get(:x))
+ b = c.binding_anyargs(0, 1)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal([0, 1], b.local_variable_get(:x))
+
+ b = c.binding_optargs(0)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal(0, b.local_variable_get(:x))
+ assert_equal(42, b.local_variable_get(:y))
+ b = c.binding_optargs(0, 1)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal(0, b.local_variable_get(:x))
+ assert_equal(1, b.local_variable_get(:y))
+
+ b = c.binding_keywords()
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal(42, b.local_variable_get(:x))
+ b = c.binding_keywords(x: 102)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal(102, b.local_variable_get(:x))
+
+ b = c.binding_anykeywords()
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal({}, b.local_variable_get(:x))
+ b = c.binding_anykeywords(foo: 999)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal({foo: 999}, b.local_variable_get(:x))
+
+ b = c.binding_forwarding()
+ assert_equal(12345, b.local_variable_get(:a))
+ b = c.binding_forwarding(0)
+ assert_equal(12345, b.local_variable_get(:a))
+ b = c.binding_forwarding(0, 1)
+ assert_equal(12345, b.local_variable_get(:a))
+ b = c.binding_forwarding(foo: 42)
+ assert_equal(12345, b.local_variable_get(:a))
+
+ b = c.binding_forwarding1(987)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal(987, b.local_variable_get(:x))
+ b = c.binding_forwarding1(987, 654)
+ assert_equal(12345, b.local_variable_get(:a))
+ assert_equal(987, b.local_variable_get(:x))
+ end
+
+ MethodInMethodClass_Setup = -> do
+ remove_const :MethodInMethodClass if defined? MethodInMethodClass
+
+ class MethodInMethodClass
+ def m1
+ def m2
+ end
+ self.class.send(:define_method, :m3){} # [Bug #11754]
+ end
+ private
+ end
+ end
+
+ def test_method_in_method_visibility_should_be_public
+ MethodInMethodClass_Setup.call
+
+ assert_equal([:m1].sort, MethodInMethodClass.public_instance_methods(false).sort)
+ assert_equal([].sort, MethodInMethodClass.private_instance_methods(false).sort)
+
+ MethodInMethodClass.new.m1
+ assert_equal([:m1, :m2, :m3].sort, MethodInMethodClass.public_instance_methods(false).sort)
+ assert_equal([].sort, MethodInMethodClass.private_instance_methods(false).sort)
+ end
+
+ def test_define_method_with_symbol
+ assert_normal_exit %q{
+ define_method(:foo, &:to_s)
+ define_method(:bar, :to_s.to_proc)
+ }, '[Bug #11850]'
+ c = Class.new{
+ define_method(:foo, &:to_s)
+ define_method(:bar, :to_s.to_proc)
+ }
+ obj = c.new
+ assert_equal('1', obj.foo(1))
+ assert_equal('1', obj.bar(1))
+ end
+
+ def test_argument_error_location
+ body = <<~'END_OF_BODY'
+ eval <<~'EOS', nil, "main.rb"
+ $line_lambda = __LINE__; $f = lambda do
+ _x = 1
+ end
+ $line_method = __LINE__; def foo
+ _x = 1
+ end
+ begin
+ $f.call(1)
+ rescue ArgumentError => e
+ assert_equal "main.rb:#{$line_lambda}:in 'block in <main>'", e.backtrace.first
+ end
+ begin
+ foo(1)
+ rescue ArgumentError => e
+ assert_equal "main.rb:#{$line_method}:in 'Object#foo'", e.backtrace.first
+ end
+ EOS
+ END_OF_BODY
+
+ assert_separately [], body
+ # without trace insn
+ assert_separately [], "RubyVM::InstructionSequence.compile_option = {trace_instruction: false}\n" + body
+ end
+
+ def test_zsuper_private_override_instance_method
+ assert_separately([], <<-'end;', timeout: 30)
+ # Bug #16942 [ruby-core:98691]
+ module M
+ def x
+ end
+ end
+
+ module M2
+ prepend Module.new
+ include M
+ private :x
+ end
+
+ ::Object.prepend(M2)
+
+ m = Object.instance_method(:x)
+ assert_equal M2, m.owner
+ end;
+ end
+
+ def test_override_optimized_method_on_class_using_prepend
+ assert_separately([], <<-'end;', timeout: 30)
+ # Bug #17725 [ruby-core:102884]
+ $VERBOSE = nil
+ String.prepend(Module.new)
+ class String
+ def + other
+ 'blah blah'
+ end
+ end
+
+ assert_equal('blah blah', 'a' + 'b')
+ end;
+ end
+
+ def test_eqq
+ assert_operator(0.method(:<), :===, 5)
+ assert_not_operator(0.method(:<), :===, -5)
+ end
+
+ def test_compose_with_method
+ c = Class.new {
+ def f(x) x * 2 end
+ def g(x) x + 1 end
+ }
+ f = c.new.method(:f)
+ g = c.new.method(:g)
+
+ assert_equal(6, (f << g).call(2))
+ assert_equal(6, (g >> f).call(2))
+ end
+
+ def test_compose_with_proc
+ c = Class.new {
+ def f(x) x * 2 end
+ }
+ f = c.new.method(:f)
+ g = proc {|x| x + 1}
+
+ assert_equal(6, (f << g).call(2))
+ assert_equal(6, (g >> f).call(2))
+ end
+
+ def test_compose_with_callable
+ c = Class.new {
+ def f(x) x * 2 end
+ }
+ c2 = Class.new {
+ def call(x) x + 1 end
+ }
+ f = c.new.method(:f)
+ g = c2.new
+
+ assert_equal(6, (f << g).call(2))
+ assert_equal(5, (f >> g).call(2))
+ end
+
+ def test_compose_with_noncallable
+ c = Class.new {
+ def f(x) x * 2 end
+ }
+ f = c.new.method(:f)
+
+ assert_raise(TypeError) {
+ f << 5
+ }
+ assert_raise(TypeError) {
+ f >> 5
+ }
+ end
+
+ def test_umethod_bind_call
+ foo = Base.instance_method(:foo)
+ assert_equal(:base, foo.bind_call(Base.new))
+ assert_equal(:base, foo.bind_call(Derived.new))
+
+ plus = Integer.instance_method(:+)
+ assert_equal(3, plus.bind_call(1, 2))
+ end
+
+ def test_method_list
+ # chkbuild lists all methods.
+ # The following code emulate this listing.
+
+ # use_symbol = Object.instance_methods[0].is_a?(Symbol)
+ nummodule = nummethod = 0
+ mods = []
+ ObjectSpace.each_object(Module) {|m| mods << m if String === m.name }
+ mods = mods.sort_by {|m| m.name }
+ mods.each {|mod|
+ nummodule += 1
+ mc = mod.kind_of?(Class) ? "class" : "module"
+ puts_line = "#{mc} #{mod.name} #{(mod.ancestors - [mod]).inspect}"
+ puts_line = puts_line # prevent unused var warning
+ mod.singleton_methods(false).sort.each {|methname|
+ nummethod += 1
+ meth = mod.method(methname)
+ line = "#{mod.name}.#{methname} #{meth.arity}"
+ line << " not-implemented" if !mod.respond_to?(methname)
+ # puts line
+ }
+ ms = mod.instance_methods(false)
+ if true or use_symbol
+ ms << :initialize if mod.private_instance_methods(false).include? :initialize
+ else
+ ms << "initialize" if mod.private_instance_methods(false).include? "initialize"
+ end
+
+ ms.sort.each {|methname|
+ nummethod += 1
+ meth = mod.instance_method(methname)
+ line = "#{mod.name}\##{methname} #{meth.arity}"
+ line << " not-implemented" if /\(not-implemented\)/ =~ meth.inspect
+ # puts line
+ }
+ }
+ # puts "#{nummodule} modules, #{nummethod} methods"
+
+ assert_operator nummodule, :>, 0
+ assert_operator nummethod, :>, 0
+ end
+
+ def test_invalidating_CC_ASAN
+ assert_ruby_status(['-e', 'using Module.new'])
+ end
+
+ def test_kwarg_eval_memory_leak
+ assert_no_memory_leak([], "", <<~RUBY, rss: true, limit: 1.2)
+ obj = Object.new
+ def obj.test(**kwargs) = nil
+
+ 100_000.times do
+ eval("obj.test(foo: 123)")
+ end
+ RUBY
+ end
+
+ def test_super_with_splat
+ c = Class.new {
+ attr_reader :x
+
+ def initialize(*args)
+ @x, _ = args
+ end
+ }
+ b = Class.new(c) { def initialize(...) = super }
+ a = Class.new(b) { def initialize(*args) = super }
+ obj = a.new(1, 2, 3)
+ assert_equal 1, obj.x
+ end
+
+ def test_warn_unused_block
+ assert_in_out_err '-w', <<-'RUBY' do |_out, err, _status|
+ def foo = nil
+ foo{} # warn
+ send(:foo){} # don't warn because it uses send
+ b = Proc.new{}
+ foo(&b) # warn
+ RUBY
+ errstr = err.join("\n")
+ assert_equal 2, err.size, errstr
+
+ assert_match(/-:2: warning/, errstr)
+ assert_match(/-:5: warning/, errstr)
+ end
+
+ assert_in_out_err '-w', <<-'RUBY' do |_out, err, _status|
+ def foo = nil
+ 10.times{foo{}} # warn once
+ RUBY
+ assert_equal 1, err.size
+ end
+
+ assert_in_out_err '-w', <<-'RUBY' do |_out, err, _status|
+ def foo = nil; b = nil
+ foo(&b) # no warning
+ 1.object_id{} # no warning because it is written in C
+
+ class C
+ def initialize
+ end
+ end
+ C.new{} # no warning
+
+ RUBY
+ assert_equal 0, err.size
+ end
+
+ assert_in_out_err '-w', <<-'RUBY' do |_out, err, _status|
+ class C0
+ def f1 = nil
+ def f2 = nil
+ def f3 = nil
+ def f4 = nil
+ def f5 = nil
+ def f6 = nil
+ end
+
+ class C1 < C0
+ def f1 = super # zsuper / use
+ def f2 = super() # super / use
+ def f3(&_) = super(&_) # super / use
+ def f4 = super(&nil) # super / unuse
+ def f5 = super(){} # super / unuse
+ def f6 = super{} # zsuper / unuse
+ end
+
+ C1.new.f1{} # no warning
+ C1.new.f2{} # no warning
+ C1.new.f3{} # no warning
+ C1.new.f4{} # warning
+ C1.new.f5{} # warning
+ C1.new.f6{} # warning
+ RUBY
+ assert_equal 3, err.size, err.join("\n")
+ assert_match(/-:22: warning.+f4/, err.join)
+ assert_match(/-:23: warning.+f5/, err.join)
+ assert_match(/-:24: warning.+f6/, err.join)
+ end
+
+ assert_in_out_err '-w', <<-'RUBY' do |_out, err, _status|
+ class C0
+ def f = yield
+ end
+
+ class C1 < C0
+ def f = nil
+ end
+
+ C1.new.f{} # do not warn on duck typing
+ RUBY
+ assert_equal 0, err.size, err.join("\n")
+ end
+
+ assert_in_out_err '-w', <<-'RUBY' do |_out, err, _status|
+ def foo(*, &block) = block
+ def bar(buz, ...) = foo(buz, ...)
+ bar(:test) {} # do not warn because of forwarding
+ RUBY
+ assert_equal 0, err.size, err.join("\n")
+ end
+ end
end