1# -*- coding: us-ascii -*- 2require 'test/unit' 3require_relative 'envutil' 4 5class TestMethod < Test::Unit::TestCase 6 def setup 7 @verbose = $VERBOSE 8 $VERBOSE = nil 9 end 10 11 def teardown 12 $VERBOSE = @verbose 13 end 14 15 def m0() end 16 def m1(a) end 17 def m2(a, b) end 18 def mo1(a = nil, &b) end 19 def mo2(a, b = nil) end 20 def mo3(*a) end 21 def mo4(a, *b, &c) end 22 def mo5(a, *b, c) end 23 def mo6(a, *b, c, &d) end 24 def mo7(a, b = nil, *c, d, &e) end 25 def ma1((a), &b) end 26 27 class Base 28 def foo() :base end 29 end 30 class Derived < Base 31 def foo() :derived end 32 end 33 class T 34 def initialize; end 35 def initialize_copy(*) super end 36 def initialize_clone(*) super end 37 def initialize_dup(*) super end 38 def respond_to_missing?(*) super end 39 def normal_method; end 40 end 41 module M 42 def func; end 43 module_function :func 44 def meth; :meth end 45 end 46 47 def mv1() end 48 def mv2() end 49 private :mv2 50 def mv3() end 51 protected :mv3 52 53 class Visibility 54 def mv1() end 55 def mv2() end 56 private :mv2 57 def mv3() end 58 protected :mv3 59 end 60 61 def test_arity 62 assert_equal(0, method(:m0).arity) 63 assert_equal(1, method(:m1).arity) 64 assert_equal(2, method(:m2).arity) 65 assert_equal(-1, method(:mo1).arity) 66 assert_equal(-2, method(:mo2).arity) 67 assert_equal(-1, method(:mo3).arity) 68 assert_equal(-2, method(:mo4).arity) 69 assert_equal(-3, method(:mo5).arity) 70 assert_equal(-3, method(:mo6).arity) 71 end 72 73 def test_arity_special 74 assert_equal(-1, method(:__send__).arity) 75 end 76 77 def test_unbind 78 assert_equal(:derived, Derived.new.foo) 79 um = Derived.new.method(:foo).unbind 80 assert_instance_of(UnboundMethod, um) 81 Derived.class_eval do 82 def foo() :changed end 83 end 84 assert_equal(:changed, Derived.new.foo) 85 assert_equal(:derived, um.bind(Derived.new).call) 86 assert_raise(TypeError) do 87 um.bind(Base.new) 88 end 89 end 90 91 def test_callee 92 assert_equal(:test_callee, __method__) 93 assert_equal(:m, Class.new {def m; __method__; end}.new.m) 94 assert_equal(:m, Class.new {def m; tap{return __method__}; end}.new.m) 95 assert_equal(:m, Class.new {define_method(:m) {__method__}}.new.m) 96 assert_equal(:m, Class.new {define_method(:m) {tap{return __method__}}}.new.m) 97 assert_nil(eval("class TestCallee; __method__; end")) 98 99 assert_equal(:test_callee, __callee__) 100 [ 101 ["method", Class.new {def m; __callee__; end},], 102 ["block", Class.new {def m; tap{return __callee__}; end},], 103 ["define_method", Class.new {define_method(:m) {__callee__}}], 104 ["define_method block", Class.new {define_method(:m) {tap{return __callee__}}}], 105 ].each do |mesg, c| 106 c.class_eval {alias m2 m} 107 o = c.new 108 assert_equal(:m, o.m, mesg) 109 assert_equal(:m2, o.m2, mesg) 110 end 111 assert_nil(eval("class TestCallee; __callee__; end")) 112 end 113 114 def test_method_in_define_method_block 115 bug4606 = '[ruby-core:35386]' 116 c = Class.new do 117 [:m1, :m2].each do |m| 118 define_method(m) do 119 __method__ 120 end 121 end 122 end 123 assert_equal(:m1, c.new.m1, bug4606) 124 assert_equal(:m2, c.new.m2, bug4606) 125 end 126 127 def test_method_in_block_in_define_method_block 128 bug4606 = '[ruby-core:35386]' 129 c = Class.new do 130 [:m1, :m2].each do |m| 131 define_method(m) do 132 tap { return __method__ } 133 end 134 end 135 end 136 assert_equal(:m1, c.new.m1, bug4606) 137 assert_equal(:m2, c.new.m2, bug4606) 138 end 139 140 def test_body 141 o = Object.new 142 def o.foo; end 143 assert_nothing_raised { RubyVM::InstructionSequence.disasm(o.method(:foo)) } 144 assert_nothing_raised { RubyVM::InstructionSequence.disasm("x".method(:upcase)) } 145 assert_nothing_raised { RubyVM::InstructionSequence.disasm(method(:to_s).to_proc) } 146 end 147 148 def test_new 149 c1 = Class.new 150 c1.class_eval { def foo; :foo; end } 151 c2 = Class.new(c1) 152 c2.class_eval { private :foo } 153 o = c2.new 154 o.extend(Module.new) 155 assert_raise(NameError) { o.method(:bar) } 156 assert_raise(NameError) { o.public_method(:foo) } 157 assert_equal(:foo, o.method(:foo).call) 158 end 159 160 def test_eq 161 o = Object.new 162 class << o 163 def foo; end 164 alias bar foo 165 def baz; end 166 end 167 assert_not_equal(o.method(:foo), nil) 168 m = o.method(:foo) 169 def m.foo; end 170 assert_not_equal(o.method(:foo), m) 171 assert_equal(o.method(:foo), o.method(:foo)) 172 assert_equal(o.method(:foo), o.method(:bar)) 173 assert_not_equal(o.method(:foo), o.method(:baz)) 174 end 175 176 def test_hash 177 o = Object.new 178 def o.foo; end 179 assert_kind_of(Integer, o.method(:foo).hash) 180 assert_equal(Array.instance_method(:map).hash, Array.instance_method(:collect).hash) 181 end 182 183 def test_owner 184 c = Class.new do 185 def foo; end 186 end 187 assert_equal(c, c.instance_method(:foo).owner) 188 c2 = Class.new(c) 189 assert_equal(c, c2.instance_method(:foo).owner) 190 end 191 192 def test_owner_missing 193 c = Class.new do 194 def respond_to_missing?(name, bool) 195 name == :foo 196 end 197 end 198 c2 = Class.new(c) 199 assert_equal(c, c.new.method(:foo).owner) 200 assert_equal(c2, c2.new.method(:foo).owner) 201 end 202 203 def test_receiver_name_owner 204 o = Object.new 205 def o.foo; end 206 m = o.method(:foo) 207 assert_equal(o, m.receiver) 208 assert_equal(:foo, m.name) 209 assert_equal(class << o; self; end, m.owner) 210 assert_equal(:foo, m.unbind.name) 211 assert_equal(class << o; self; end, m.unbind.owner) 212 end 213 214 def test_instance_method 215 c = Class.new 216 c.class_eval do 217 def foo; :foo; end 218 private :foo 219 end 220 o = c.new 221 o.method(:foo).unbind 222 assert_raise(NoMethodError) { o.foo } 223 c.instance_method(:foo).bind(o) 224 assert_equal(:foo, o.instance_eval { foo }) 225 assert_raise(NameError) { c.public_instance_method(:foo) } 226 def o.bar; end 227 m = o.method(:bar).unbind 228 assert_raise(TypeError) { m.bind(Object.new) } 229 230 feature4254 = '[ruby-core:34267]' 231 m = M.instance_method(:meth) 232 assert_equal(:meth, m.bind(Object.new).call, feature4254) 233 end 234 235 def test_define_method 236 c = Class.new 237 c.class_eval { def foo; :foo; end } 238 o = c.new 239 def o.bar; :bar; end 240 assert_raise(TypeError) do 241 c.class_eval { define_method(:foo, :foo) } 242 end 243 assert_raise(ArgumentError) do 244 c.class_eval { define_method } 245 end 246 c2 = Class.new(c) 247 c2.class_eval { define_method(:baz, o.method(:foo)) } 248 assert_equal(:foo, c2.new.baz) 249 assert_raise(TypeError) do 250 Class.new.class_eval { define_method(:foo, o.method(:foo)) } 251 end 252 assert_raise(TypeError) do 253 Class.new.class_eval { define_method(:bar, o.method(:bar)) } 254 end 255 end 256 257 def test_define_singleton_method 258 o = Object.new 259 def o.foo(c) 260 c.class_eval { define_method(:foo) } 261 end 262 c = Class.new 263 o.foo(c) { :foo } 264 assert_equal(:foo, c.new.foo) 265 266 o = Object.new 267 o.instance_eval { define_singleton_method(:foo) { :foo } } 268 assert_equal(:foo, o.foo) 269 270 assert_raise(TypeError) do 271 Class.new.class_eval { define_method(:foo, Object.new) } 272 end 273 274 assert_raise(TypeError) do 275 Module.new.module_eval {define_method(:foo, Base.instance_method(:foo))} 276 end 277 end 278 279 def test_define_singleton_method_with_extended_method 280 bug8686 = "[ruby-core:56174]" 281 282 m = Module.new do 283 extend self 284 285 def a 286 "a" 287 end 288 end 289 290 assert_nothing_raised do 291 m.define_singleton_method(:a, m.method(:a)) 292 end 293 end 294 295 def test_define_method_transplating 296 feature4254 = '[ruby-core:34267]' 297 m = Module.new {define_method(:meth, M.instance_method(:meth))} 298 assert_equal(:meth, Object.new.extend(m).meth, feature4254) 299 c = Class.new {define_method(:meth, M.instance_method(:meth))} 300 assert_equal(:meth, c.new.meth, feature4254) 301 end 302 303 def test_super_in_proc_from_define_method 304 c1 = Class.new { 305 def m 306 :m1 307 end 308 } 309 c2 = Class.new(c1) { define_method(:m) { Proc.new { super() } } } 310 # c2.new.m.call should return :m1, but currently it raise NoMethodError. 311 # see [Bug #4881] and [Bug #3136] 312 assert_raise(NoMethodError) { 313 c2.new.m.call 314 } 315 end 316 317 def test_clone 318 o = Object.new 319 def o.foo; :foo; end 320 m = o.method(:foo) 321 def m.bar; :bar; end 322 assert_equal(:foo, m.clone.call) 323 assert_equal(:bar, m.clone.bar) 324 end 325 326 def test_call 327 o = Object.new 328 def o.foo; p 1; end 329 def o.bar(x); x; end 330 m = o.method(:foo) 331 m.taint 332 assert_raise(SecurityError) { m.call } 333 end 334 335 def test_inspect 336 o = Object.new 337 def o.foo; end 338 m = o.method(:foo) 339 assert_equal("#<Method: #{ o.inspect }.foo>", m.inspect) 340 m = o.method(:foo) 341 assert_equal("#<UnboundMethod: #{ class << o; self; end.inspect }#foo>", m.unbind.inspect) 342 343 c = Class.new 344 c.class_eval { def foo; end; } 345 m = c.new.method(:foo) 346 assert_equal("#<Method: #{ c.inspect }#foo>", m.inspect) 347 m = c.instance_method(:foo) 348 assert_equal("#<UnboundMethod: #{ c.inspect }#foo>", m.inspect) 349 350 c2 = Class.new(c) 351 c2.class_eval { private :foo } 352 m2 = c2.new.method(:foo) 353 assert_equal("#<Method: #{ c2.inspect }(#{ c.inspect })#foo>", m2.inspect) 354 end 355 356 def test_callee_top_level 357 assert_in_out_err([], "p __callee__", %w(nil), []) 358 end 359 360 def test_caller_top_level 361 assert_in_out_err([], "p caller", %w([]), []) 362 end 363 364 def test_caller_negative_level 365 assert_raise(ArgumentError) { caller(-1) } 366 end 367 368 def test_attrset_ivar 369 c = Class.new 370 c.class_eval { attr_accessor :foo } 371 o = c.new 372 o.method(:foo=).call(42) 373 assert_equal(42, o.foo) 374 assert_raise(ArgumentError) { o.method(:foo=).call(1, 2, 3) } 375 assert_raise(ArgumentError) { o.method(:foo).call(1) } 376 end 377 378 def test_default_accessibility 379 assert T.public_instance_methods.include?(:normal_method), 'normal methods are public by default' 380 assert !T.public_instance_methods.include?(:initialize), '#initialize is private' 381 assert !T.public_instance_methods.include?(:initialize_copy), '#initialize_copy is private' 382 assert !T.public_instance_methods.include?(:initialize_clone), '#initialize_clone is private' 383 assert !T.public_instance_methods.include?(:initialize_dup), '#initialize_dup is private' 384 assert !T.public_instance_methods.include?(:respond_to_missing?), '#respond_to_missing? is private' 385 assert !M.public_instance_methods.include?(:func), 'module methods are private by default' 386 assert M.public_instance_methods.include?(:meth), 'normal methods are public by default' 387 end 388 389 define_method(:pm0) {||} 390 define_method(:pm1) {|a|} 391 define_method(:pm2) {|a, b|} 392 define_method(:pmo1) {|a = nil, &b|} 393 define_method(:pmo2) {|a, b = nil|} 394 define_method(:pmo3) {|*a|} 395 define_method(:pmo4) {|a, *b, &c|} 396 define_method(:pmo5) {|a, *b, c|} 397 define_method(:pmo6) {|a, *b, c, &d|} 398 define_method(:pmo7) {|a, b = nil, *c, d, &e|} 399 define_method(:pma1) {|(a), &b|} 400 401 def test_bound_parameters 402 assert_equal([], method(:m0).parameters) 403 assert_equal([[:req, :a]], method(:m1).parameters) 404 assert_equal([[:req, :a], [:req, :b]], method(:m2).parameters) 405 assert_equal([[:opt, :a], [:block, :b]], method(:mo1).parameters) 406 assert_equal([[:req, :a], [:opt, :b]], method(:mo2).parameters) 407 assert_equal([[:rest, :a]], method(:mo3).parameters) 408 assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:mo4).parameters) 409 assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:mo5).parameters) 410 assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:mo6).parameters) 411 assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:mo7).parameters) 412 assert_equal([[:req], [:block, :b]], method(:ma1).parameters) 413 end 414 415 def test_unbound_parameters 416 assert_equal([], self.class.instance_method(:m0).parameters) 417 assert_equal([[:req, :a]], self.class.instance_method(:m1).parameters) 418 assert_equal([[:req, :a], [:req, :b]], self.class.instance_method(:m2).parameters) 419 assert_equal([[:opt, :a], [:block, :b]], self.class.instance_method(:mo1).parameters) 420 assert_equal([[:req, :a], [:opt, :b]], self.class.instance_method(:mo2).parameters) 421 assert_equal([[:rest, :a]], self.class.instance_method(:mo3).parameters) 422 assert_equal([[:req, :a], [:rest, :b], [:block, :c]], self.class.instance_method(:mo4).parameters) 423 assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:mo5).parameters) 424 assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:mo6).parameters) 425 assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:mo7).parameters) 426 assert_equal([[:req], [:block, :b]], self.class.instance_method(:ma1).parameters) 427 end 428 429 def test_bmethod_bound_parameters 430 assert_equal([], method(:pm0).parameters) 431 assert_equal([[:req, :a]], method(:pm1).parameters) 432 assert_equal([[:req, :a], [:req, :b]], method(:pm2).parameters) 433 assert_equal([[:opt, :a], [:block, :b]], method(:pmo1).parameters) 434 assert_equal([[:req, :a], [:opt, :b]], method(:pmo2).parameters) 435 assert_equal([[:rest, :a]], method(:pmo3).parameters) 436 assert_equal([[:req, :a], [:rest, :b], [:block, :c]], method(:pmo4).parameters) 437 assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:pmo5).parameters) 438 assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).parameters) 439 assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).parameters) 440 assert_equal([[:req], [:block, :b]], method(:pma1).parameters) 441 end 442 443 def test_bmethod_unbound_parameters 444 assert_equal([], self.class.instance_method(:pm0).parameters) 445 assert_equal([[:req, :a]], self.class.instance_method(:pm1).parameters) 446 assert_equal([[:req, :a], [:req, :b]], self.class.instance_method(:pm2).parameters) 447 assert_equal([[:opt, :a], [:block, :b]], self.class.instance_method(:pmo1).parameters) 448 assert_equal([[:req, :a], [:opt, :b]], self.class.instance_method(:pmo2).parameters) 449 assert_equal([[:rest, :a]], self.class.instance_method(:pmo3).parameters) 450 assert_equal([[:req, :a], [:rest, :b], [:block, :c]], self.class.instance_method(:pmo4).parameters) 451 assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:pmo5).parameters) 452 assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:pmo6).parameters) 453 assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:pmo7).parameters) 454 assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters) 455 end 456 457 def test_public_method_with_zsuper_method 458 c = Class.new 459 c.class_eval do 460 def foo 461 :ok 462 end 463 private :foo 464 end 465 d = Class.new(c) 466 d.class_eval do 467 public :foo 468 end 469 assert_equal(:ok, d.new.public_method(:foo).call) 470 end 471 472 def test_public_methods_with_extended 473 m = Module.new do def m1; end end 474 a = Class.new do def a; end end 475 bug = '[ruby-dev:41553]' 476 obj = a.new 477 assert_equal([:a], obj.public_methods(false), bug) 478 obj.extend(m) 479 assert_equal([:m1, :a], obj.public_methods(false), bug) 480 end 481 482 def test_visibility 483 assert_equal('method', defined?(mv1)) 484 assert_equal('method', defined?(mv2)) 485 assert_equal('method', defined?(mv3)) 486 487 assert_equal('method', defined?(self.mv1)) 488 assert_equal(nil, defined?(self.mv2)) 489 assert_equal('method', defined?(self.mv3)) 490 491 assert_equal(true, respond_to?(:mv1)) 492 assert_equal(false, respond_to?(:mv2)) 493 assert_equal(false, respond_to?(:mv3)) 494 495 assert_equal(true, respond_to?(:mv1, true)) 496 assert_equal(true, respond_to?(:mv2, true)) 497 assert_equal(true, respond_to?(:mv3, true)) 498 499 assert_nothing_raised { mv1 } 500 assert_nothing_raised { mv2 } 501 assert_nothing_raised { mv3 } 502 503 assert_nothing_raised { self.mv1 } 504 assert_raise(NoMethodError) { self.mv2 } 505 assert_nothing_raised { self.mv3 } 506 507 v = Visibility.new 508 509 assert_equal('method', defined?(v.mv1)) 510 assert_equal(nil, defined?(v.mv2)) 511 assert_equal(nil, defined?(v.mv3)) 512 513 assert_equal(true, v.respond_to?(:mv1)) 514 assert_equal(false, v.respond_to?(:mv2)) 515 assert_equal(false, v.respond_to?(:mv3)) 516 517 assert_equal(true, v.respond_to?(:mv1, true)) 518 assert_equal(true, v.respond_to?(:mv2, true)) 519 assert_equal(true, v.respond_to?(:mv3, true)) 520 521 assert_nothing_raised { v.mv1 } 522 assert_raise(NoMethodError) { v.mv2 } 523 assert_raise(NoMethodError) { v.mv3 } 524 525 assert_nothing_raised { v.__send__(:mv1) } 526 assert_nothing_raised { v.__send__(:mv2) } 527 assert_nothing_raised { v.__send__(:mv3) } 528 529 assert_nothing_raised { v.instance_eval { mv1 } } 530 assert_nothing_raised { v.instance_eval { mv2 } } 531 assert_nothing_raised { v.instance_eval { mv3 } } 532 end 533 534 def test_bound_method_entry 535 bug6171 = '[ruby-core:43383]' 536 assert_ruby_status([], <<-EOC, bug6171) 537 class Bug6171 538 def initialize(target) 539 define_singleton_method(:reverse, target.method(:reverse).to_proc) 540 end 541 end 542 100.times {p = Bug6171.new('test'); 1000.times {p.reverse}} 543 EOC 544 end 545 546 def test___dir__ 547 assert_instance_of String, __dir__ 548 assert_equal(File.dirname(File.realpath(__FILE__)), __dir__) 549 bug8436 = '[ruby-core:55123] [Bug #8436]' 550 assert_equal(__dir__, eval("__dir__", binding), bug8436) 551 bug8662 = '[ruby-core:56099] [Bug #8662]' 552 assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662) 553 assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662) 554 end 555 556 def test_alias_owner 557 bug7613 = '[ruby-core:51105]' 558 bug7993 = '[Bug #7993]' 559 c = Class.new { 560 def foo 561 end 562 prepend Module.new 563 attr_reader :zot 564 } 565 x = c.new 566 class << x 567 alias bar foo 568 end 569 assert_equal(c, c.instance_method(:foo).owner) 570 assert_equal(c, x.method(:foo).owner) 571 assert_equal(x.singleton_class, x.method(:bar).owner) 572 assert(x.method(:foo) != x.method(:bar), bug7613) 573 assert_equal(c, x.method(:zot).owner, bug7993) 574 assert_equal(c, c.instance_method(:zot).owner, bug7993) 575 end 576 577 def test_gced_bmethod 578 assert_normal_exit %q{ 579 require 'irb' 580 IRB::Irb.module_eval do 581 define_method(:eval_input) do 582 IRB::Irb.module_eval { alias_method :eval_input, :to_s } 583 GC.start 584 Kernel 585 end 586 end 587 IRB.start 588 }, '[Bug #7825]' 589 end 590 591 def test_unlinked_method_entry_in_method_object_bug 592 bug8100 = '[ruby-core:53640] [Bug #8100]' 593 assert_ruby_status [], %q{ 594 loop do 595 def x 596 "hello" * 1000 597 end 598 method(:x).call 599 end 600 }, bug8100, timeout: 2 601 rescue Timeout::Error 602 end 603end 604