diff options
Diffstat (limited to 'test/ruby/test_object.rb')
| -rw-r--r-- | test/ruby/test_object.rb | 527 |
1 files changed, 332 insertions, 195 deletions
diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb index 4e958a7f7b..83208bbcdb 100644 --- a/test/ruby/test_object.rb +++ b/test/ruby/test_object.rb @@ -1,26 +1,117 @@ +# -*- coding: us-ascii -*- +# frozen_string_literal: false require 'test/unit' -require_relative 'envutil' class TestObject < Test::Unit::TestCase def setup @verbose = $VERBOSE - $VERBOSE = nil end def teardown $VERBOSE = @verbose end + def test_itself + feature6373 = '[ruby-core:44704] [Feature #6373]' + object = Object.new + assert_same(object, object.itself, feature6373) + end + + def test_yield_self + feature = '[ruby-core:46320] [Feature #6721]' + object = Object.new + assert_same(self, object.yield_self {self}, feature) + assert_same(object, object.yield_self {|x| break x}, feature) + enum = object.yield_self + assert_instance_of(Enumerator, enum) + assert_equal(1, enum.size) + end + def test_dup - assert_raise(TypeError) { 1.dup } - assert_raise(TypeError) { true.dup } - assert_raise(TypeError) { nil.dup } + assert_equal 1, 1.dup + assert_equal true, true.dup + assert_equal nil, nil.dup + assert_equal false, false.dup + x = :x; assert_equal x, x.dup + x = "bug13145".intern; assert_equal x, x.dup + x = 1 << 64; assert_equal x, x.dup + x = 1.72723e-77; assert_equal x, x.dup assert_raise(TypeError) do Object.new.instance_eval { initialize_copy(1) } end end + def test_clone + a = Object.new + def a.b; 2 end + + c = a.clone + assert_equal(false, c.frozen?) + assert_equal(false, a.frozen?) + assert_equal(2, c.b) + + c = a.clone(freeze: true) + assert_equal(true, c.frozen?) + assert_equal(false, a.frozen?) + assert_equal(2, c.b) + + a.freeze + c = a.clone + assert_equal(true, c.frozen?) + assert_equal(true, a.frozen?) + assert_equal(2, c.b) + + assert_raise(ArgumentError) {a.clone(freeze: [])} + d = a.clone(freeze: false) + def d.e; 3; end + assert_equal(false, d.frozen?) + assert_equal(true, a.frozen?) + assert_equal(2, d.b) + assert_equal(3, d.e) + + assert_equal 1, 1.clone + assert_equal true, true.clone + assert_equal nil, nil.clone + assert_equal false, false.clone + x = :x; assert_equal x, x.dup + x = "bug13145".intern; assert_equal x, x.dup + x = 1 << 64; assert_equal x, x.clone + x = 1.72723e-77; assert_equal x, x.clone + assert_raise(ArgumentError) {1.clone(freeze: false)} + assert_raise(ArgumentError) {true.clone(freeze: false)} + assert_raise(ArgumentError) {nil.clone(freeze: false)} + assert_raise(ArgumentError) {false.clone(freeze: false)} + x = EnvUtil.labeled_class("\u{1f4a9}").new + assert_raise_with_message(ArgumentError, /\u{1f4a9}/) do + Object.new.clone(freeze: x) + end + + c = Class.new do + attr_reader :f + end + o = c.new + def o.initialize_clone(_, freeze: true) + @f = freeze + super + end + clone = o.clone + assert_kind_of c, clone + assert_equal true, clone.f + clone = o.clone(freeze: false) + assert_kind_of c, clone + assert_equal false, clone.f + + class << o + remove_method(:initialize_clone) + end + def o.initialize_clone(_) + super + end + assert_kind_of c, o.clone + assert_raise(ArgumentError) { o.clone(freeze: false) } + end + def test_init_dupclone cls = Class.new do def initialize_clone(orig); throw :initialize_clone; end @@ -28,8 +119,8 @@ class TestObject < Test::Unit::TestCase end obj = cls.new - assert_throws(:initialize_clone) {obj.clone} - assert_throws(:initialize_dup) {obj.dup} + assert_throw(:initialize_clone) {obj.clone} + assert_throw(:initialize_dup) {obj.dup} end def test_instance_of @@ -40,38 +131,52 @@ class TestObject < Test::Unit::TestCase assert_raise(TypeError) { 1.kind_of?(1) } end - def test_taint_frozen_obj - o = Object.new - o.freeze - assert_raise(RuntimeError) { o.taint } - - o = Object.new - o.taint - o.freeze - assert_raise(RuntimeError) { o.untaint } - end - - def test_freeze_under_safe_4 - o = Object.new - assert_raise(SecurityError) do - Thread.new do - $SAFE = 4 - o.freeze - end.join - end - end - def test_freeze_immediate assert_equal(true, 1.frozen?) 1.freeze assert_equal(true, 1.frozen?) assert_equal(true, 2.frozen?) + assert_equal(true, true.frozen?) + assert_equal(true, false.frozen?) + assert_equal(true, nil.frozen?) + end + + def test_frozen_error_message + name = "C\u{30c6 30b9 30c8}" + klass = EnvUtil.labeled_class(name) { + attr_accessor :foo + } + obj = klass.new.freeze + assert_raise_with_message(FrozenError, /#{name}/) { + obj.foo = 1 + } end def test_nil_to_f assert_equal(0.0, nil.to_f) end + def test_nil_to_s + str = nil.to_s + assert_equal("", str) + assert_predicate(str, :frozen?) + assert_same(str, nil.to_s) + end + + def test_true_to_s + str = true.to_s + assert_equal("true", str) + assert_predicate(str, :frozen?) + assert_same(str, true.to_s) + end + + def test_false_to_s + str = false.to_s + assert_equal("false", str) + assert_predicate(str, :frozen?) + assert_same(str, false.to_s) + end + def test_not assert_equal(false, Object.new.send(:!)) assert_equal(true, nil.send(:!)) @@ -158,19 +263,57 @@ class TestObject < Test::Unit::TestCase assert_equal([:foo2], (o2.public_methods(false) - o0.public_methods(false)).sort) end + def test_methods_prepend + bug8044 = '[ruby-core:53207] [Bug #8044]' + o = Object.new + def o.foo; end + assert_equal([:foo], o.methods(false)) + class << o; prepend Module.new; end + assert_equal([:foo], o.methods(false), bug8044) + end + + def test_methods_prepend_singleton + c = Class.new(Module) {private def foo; end} + k = c.new + k.singleton_class + c.module_eval {prepend(Module.new)} + assert_equal([:foo], k.private_methods(false)) + end + def test_instance_variable_get o = Object.new o.instance_eval { @foo = :foo } assert_equal(:foo, o.instance_variable_get(:@foo)) assert_equal(nil, o.instance_variable_get(:@bar)) + assert_raise(NameError) { o.instance_variable_get('@') } + assert_raise(NameError) { o.instance_variable_get(:'@') } assert_raise(NameError) { o.instance_variable_get(:foo) } + assert_raise(NameError) { o.instance_variable_get("bar") } + assert_raise(TypeError) { o.instance_variable_get(1) } + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end + def n.count; @count; end + assert_equal(:foo, o.instance_variable_get(n)) + assert_equal(1, n.count) end def test_instance_variable_set o = Object.new o.instance_variable_set(:@foo, :foo) assert_equal(:foo, o.instance_eval { @foo }) + assert_raise(NameError) { o.instance_variable_set(:'@', 1) } + assert_raise(NameError) { o.instance_variable_set('@', 1) } assert_raise(NameError) { o.instance_variable_set(:foo, 1) } + assert_raise(NameError) { o.instance_variable_set("bar", 1) } + assert_raise(TypeError) { o.instance_variable_set(1, 1) } + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end + def n.count; @count; end + o.instance_variable_set(n, :bar) + assert_equal(:bar, o.instance_eval { @foo }) + assert_equal(1, n.count) end def test_instance_variable_defined @@ -178,32 +321,62 @@ class TestObject < Test::Unit::TestCase o.instance_eval { @foo = :foo } assert_equal(true, o.instance_variable_defined?(:@foo)) assert_equal(false, o.instance_variable_defined?(:@bar)) + assert_raise(NameError) { o.instance_variable_defined?(:'@') } + assert_raise(NameError) { o.instance_variable_defined?('@') } assert_raise(NameError) { o.instance_variable_defined?(:foo) } + assert_raise(NameError) { o.instance_variable_defined?("bar") } + assert_raise(TypeError) { o.instance_variable_defined?(1) } + + n = Object.new + def n.to_str; @count = defined?(@count) ? @count + 1 : 1; "@foo"; end + def n.count; @count; end + assert_equal(true, o.instance_variable_defined?(n)) + assert_equal(1, n.count) end def test_remove_instance_variable - o = Object.new - o.instance_eval { @foo = :foo } - o.instance_eval { remove_instance_variable(:@foo) } - assert_equal(false, o.instance_variable_defined?(:@foo)) + { 'T_OBJECT' => Object.new, + 'T_CLASS,T_MODULE' => Class.new(Object), + 'generic ivar' => '', + }.each do |desc, o| + e = assert_raise(NameError, "#{desc} iv removal raises before set") do + o.remove_instance_variable(:@foo) + end + assert_equal([o, :@foo], [e.receiver, e.name]) + o.instance_eval { @foo = :foo } + assert_equal(:foo, o.remove_instance_variable(:@foo), + "#{desc} iv removal returns original value") + assert_not_send([o, :instance_variable_defined?, :@foo], + "#{desc} iv removed successfully") + e = assert_raise(NameError, "#{desc} iv removal raises after removal") do + o.remove_instance_variable(:@foo) + end + assert_equal([o, :@foo], [e.receiver, e.name]) + end end - def test_convert_type + def test_convert_string o = Object.new def o.to_s; 1; end assert_raise(TypeError) { String(o) } + o.singleton_class.remove_method(:to_s) def o.to_s; "o"; end assert_equal("o", String(o)) + def o.to_str; "O"; end + assert_equal("O", String(o)) def o.respond_to?(*) false; end assert_raise(TypeError) { String(o) } end - def test_check_convert_type + def test_convert_array o = Object.new def o.to_a; 1; end assert_raise(TypeError) { Array(o) } + o.singleton_class.remove_method(:to_a) def o.to_a; [1]; end assert_equal([1], Array(o)) + def o.to_ary; [2]; end + assert_equal([2], Array(o)) def o.respond_to?(*) false; end assert_equal([o], Array(o)) end @@ -217,6 +390,7 @@ class TestObject < Test::Unit::TestCase o = Object.new def o.to_hash; {a: 1, b: 2}; end assert_equal({a: 1, b: 2}, Hash(o)) + o.singleton_class.remove_method(:to_hash) def o.to_hash; 9; end assert_raise(TypeError) { Hash(o) } end @@ -225,6 +399,7 @@ class TestObject < Test::Unit::TestCase o = Object.new def o.to_i; nil; end assert_raise(TypeError) { Integer(o) } + o.singleton_class.remove_method(:to_i) def o.to_i; 42; end assert_equal(42, Integer(o)) def o.respond_to?(*) false; end @@ -247,17 +422,6 @@ class TestObject < Test::Unit::TestCase assert_equal(1+3+5+7+9, n) end - def test_add_method_under_safe4 - o = Object.new - assert_raise(SecurityError) do - Thread.new do - $SAFE = 4 - def o.foo - end - end.join - end - end - def test_redefine_method_under_verbose assert_in_out_err([], <<-INPUT, %w(2), /warning: method redefined; discarding old foo$/) $VERBOSE = true @@ -269,35 +433,30 @@ class TestObject < Test::Unit::TestCase end def test_redefine_method_which_may_case_serious_problem - assert_in_out_err([], <<-INPUT, [], /warning: redefining `object_id' may cause serious problems$/) + assert_in_out_err([], <<-INPUT, [], %r"warning: redefining `object_id' may cause serious problems$") $VERBOSE = false def (Object.new).object_id; end INPUT - assert_in_out_err([], <<-INPUT, [], /warning: redefining `__send__' may cause serious problems$/) + assert_in_out_err([], <<-INPUT, [], %r"warning: redefining `__send__' may cause serious problems$") $VERBOSE = false def (Object.new).__send__; end INPUT + + bug10421 = '[ruby-dev:48691] [Bug #10421]' + assert_in_out_err([], <<-INPUT, ["1"], [], bug10421) + $VERBOSE = false + class C < BasicObject + def object_id; 1; end + end + puts C.new.object_id + INPUT end def test_remove_method - assert_raise(SecurityError) do - Thread.new do - $SAFE = 4 - Object.instance_eval { remove_method(:foo) } - end.join - end - - assert_raise(SecurityError) do - Thread.new do - $SAFE = 4 - Class.instance_eval { remove_method(:foo) } - end.join - end - c = Class.new c.freeze - assert_raise(RuntimeError) do + assert_raise(FrozenError) do c.instance_eval { remove_method(:foo) } end @@ -322,7 +481,7 @@ class TestObject < Test::Unit::TestCase assert_raise(NoMethodError, bug2202) {o2.meth2} %w(object_id __send__ initialize).each do |m| - assert_in_out_err([], <<-INPUT, %w(:ok), /warning: removing `#{m}' may cause serious problems$/) + assert_in_out_err([], <<-INPUT, %w(:ok), %r"warning: removing `#{m}' may cause serious problems$") $VERBOSE = false begin Class.new.instance_eval { remove_method(:#{m}) } @@ -331,6 +490,19 @@ class TestObject < Test::Unit::TestCase end INPUT end + + m = "\u{30e1 30bd 30c3 30c9}" + c = Class.new + assert_raise_with_message(NameError, /#{m}/) do + c.class_eval {remove_method m} + end + c = Class.new { + define_method(m) {} + remove_method(m) + } + assert_raise_with_message(NameError, /#{m}/) do + c.class_eval {remove_method m} + end end def test_method_missing @@ -405,8 +577,8 @@ class TestObject < Test::Unit::TestCase assert_equal([:foo], foo.foobar); assert_equal([:foo, 1], foo.foobar(1)); assert_equal([:foo, 1, 2, 3, 4, 5], foo.foobar(1, 2, 3, 4, 5)); - assert(foo.respond_to?(:foobar)) - assert_equal(false, foo.respond_to?(:foobarbaz)) + assert_respond_to(foo, :foobar) + assert_not_respond_to(foo, :foobarbaz) assert_raise(NoMethodError) do foo.foobarbaz end @@ -462,7 +634,7 @@ class TestObject < Test::Unit::TestCase called = [] p.singleton_class.class_eval do - define_method(:respond_to?) do |a| + define_method(:respond_to?) do |a, priv = false| called << [:respond_to?, a] false end @@ -482,11 +654,10 @@ class TestObject < Test::Unit::TestCase end end - e = assert_raise(ArgumentError, '[bug:6000]') do + msg = 'respond_to? must accept 1 or 2 arguments (requires 3)' + assert_raise_with_message(ArgumentError, msg, '[bug:6000]') do [[p]].flatten end - - assert_equal('respond_to? must accept 1 or 2 arguments (requires 3)', e.message) end def test_method_missing_passed_block @@ -557,11 +728,39 @@ class TestObject < Test::Unit::TestCase end begin nil.public_send(o) { x = :ng } - rescue + rescue TypeError end assert_equal(:ok, x) end + def test_public_send + c = Class.new do + def pub + :ok + end + + def invoke(m) + public_send(m) + end + + protected + def prot + :ng + end + + private + def priv + :ng + end + end.new + assert_equal(:ok, c.public_send(:pub)) + assert_raise(NoMethodError) {c.public_send(:priv)} + assert_raise(NoMethodError) {c.public_send(:prot)} + assert_raise(NoMethodError) {c.invoke(:priv)} + bug7499 = '[ruby-core:50489]' + assert_raise(NoMethodError, bug7499) {c.invoke(:prot)} + end + def test_no_superclass_method bug2312 = '[ruby-dev:39581]' @@ -578,7 +777,7 @@ class TestObject < Test::Unit::TestCase e = assert_raise(NoMethodError) { o.never_defined_test_no_superclass_method } - assert_equal(m1, e.message, bug2312) + assert_equal(m1.lines.first, e.message.lines.first, bug2312) end def test_superclass_method @@ -623,89 +822,19 @@ class TestObject < Test::Unit::TestCase end end - def test_untrusted - obj = lambda { - $SAFE = 4 - x = Object.new - x.instance_eval { @foo = 1 } - x - }.call - assert_equal(true, obj.untrusted?) - assert_equal(true, obj.tainted?) - - x = Object.new - assert_equal(false, x.untrusted?) - assert_raise(SecurityError) do - lambda { - $SAFE = 4 - x.instance_eval { @foo = 1 } - }.call - end - - x = Object.new - x.taint - assert_raise(SecurityError) do - lambda { - $SAFE = 4 - x.instance_eval { @foo = 1 } - }.call - end - - x.untrust - assert_equal(true, x.untrusted?) - assert_nothing_raised do - lambda { - $SAFE = 4 - x.instance_eval { @foo = 1 } - }.call - end - - x.trust - assert_equal(false, x.untrusted?) - assert_raise(SecurityError) do - lambda { - $SAFE = 4 - x.instance_eval { @foo = 1 } - }.call - end - - a = Object.new - a.untrust - assert_equal(true, a.untrusted?) - b = a.dup - assert_equal(true, b.untrusted?) - c = a.clone - assert_equal(true, c.untrusted?) - - a = Object.new - b = lambda { - $SAFE = 4 - a.dup - }.call - assert_equal(true, b.untrusted?) - - a = Object.new - b = lambda { - $SAFE = 4 - a.clone - }.call - assert_equal(true, b.untrusted?) - end - def test_to_s - x = Object.new - x.taint - x.untrust - s = x.to_s - assert_equal(true, s.untrusted?) - assert_equal(true, s.tainted?) - x = eval(<<-EOS) class ToS\u{3042} new.to_s end EOS assert_match(/\bToS\u{3042}:/, x) + + name = "X".freeze + x = Object.new + class<<x;self;end.class_eval {define_method(:to_s) {name}} + assert_same(name, x.to_s) + assert_equal("X", [x].join("")) end def test_inspect @@ -744,46 +873,35 @@ class TestObject < Test::Unit::TestCase def initialize @\u{3044} = 42 end - new.inspect + new end EOS - assert_match(/\bInspect\u{3042}:.* @\u{3044}=42\b/, x) + assert_match(/\bInspect\u{3042}:.* @\u{3044}=42\b/, x.inspect) + x.instance_variable_set("@\u{3046}".encode(Encoding::EUC_JP), 6) + assert_match(/@\u{3046}=6\b/, x.inspect) end - def test_exec_recursive - Thread.current[:__recursive_key__] = nil - a = [[]] - a.inspect - - assert_nothing_raised do - -> do - $SAFE = 4 - begin - a.hash - rescue ArgumentError - end - end.call - end + def test_singleton_methods + assert_equal([], Object.new.singleton_methods) + assert_equal([], Object.new.singleton_methods(false)) + c = Class.new + def c.foo; end + assert_equal([:foo], c.singleton_methods - [:yaml_tag]) + assert_equal([:foo], c.singleton_methods(false)) + assert_equal([], c.singleton_class.singleton_methods(false)) + c.singleton_class.singleton_class + assert_equal([], c.singleton_class.singleton_methods(false)) - -> do - assert_nothing_raised do - $SAFE = 4 - a.inspect - end - end.call + o = c.new.singleton_class + assert_equal([:foo], o.singleton_methods - [:yaml_tag]) + assert_equal([], o.singleton_methods(false)) + o.singleton_class + assert_equal([:foo], o.singleton_methods - [:yaml_tag]) + assert_equal([], o.singleton_methods(false)) - -> do - o = Object.new - def o.to_ary(x); end - def o.==(x); $SAFE = 4; false; end - a = [[o]] - b = [] - b << b - - assert_nothing_raised do - b == a - end - end.call + c.extend(Module.new{def bar; end}) + assert_equal([:bar, :foo], c.singleton_methods.sort - [:yaml_tag]) + assert_equal([:foo], c.singleton_methods(false)) end def test_singleton_class @@ -810,18 +928,17 @@ class TestObject < Test::Unit::TestCase def test_redef_method_missing bug5473 = '[ruby-core:40287]' ['ArgumentError.new("bug5473")', 'ArgumentError, "bug5473"', '"bug5473"'].each do |code| - out, err, status = EnvUtil.invoke_ruby([], <<-SRC, true, true) + exc = code[/\A[A-Z]\w+/] || 'RuntimeError' + assert_separately([], <<-SRC) + $VERBOSE = nil class ::Object def method_missing(m, *a, &b) raise #{code} end end - p((1.foo rescue $!)) + assert_raise_with_message(#{exc}, "bug5473", #{bug5473.dump}) {1.foo} SRC - assert_send([status, :success?], bug5473) - assert_equal("", err, bug5473) - assert_equal((eval("raise #{code}") rescue $!.inspect), out.chomp, bug5473) end end @@ -830,14 +947,8 @@ class TestObject < Test::Unit::TestCase b = yield assert_nothing_raised("copy") {a.instance_eval {initialize_copy(b)}} c = a.dup.freeze - assert_raise(RuntimeError, "frozen") {c.instance_eval {initialize_copy(b)}} - d = a.dup.trust - assert_raise(SecurityError, "untrust") do - proc { - $SAFE = 4 - d.instance_eval {initialize_copy(b)} - }.call - end + assert_raise(FrozenError, "frozen") {c.instance_eval {initialize_copy(b)}} + d = a.dup [a, b, c, d] end @@ -854,6 +965,32 @@ class TestObject < Test::Unit::TestCase assert_not_initialize_copy {/.*/.match("foo")} st = Struct.new(:foo) assert_not_initialize_copy {st.new} - assert_not_initialize_copy {Time.now} + end + + def test_type_error_message + _issue = "Bug #7539" + assert_raise_with_message(TypeError, "can't convert Array into Integer") {Integer([42])} + assert_raise_with_message(TypeError, 'no implicit conversion of Array into Integer') {[].first([42])} + assert_raise_with_message(TypeError, "can't convert Array into Rational") {Rational([42])} + end + + def test_copied_ivar_memory_leak + bug10191 = '[ruby-core:64700] [Bug #10191]' + assert_no_memory_leak([], <<-"end;", <<-"end;", bug10191, timeout: 60, limit: 1.8) + def (a = Object.new).set; @v = nil; end + num = 500_000 + end; + num.times {a.clone.set} + end; + end + + def test_clone_object_should_not_be_old + assert_normal_exit <<-EOS, '[Bug #13775]' + b = proc { } + 10.times do |i| + b.clone + GC.start + end + EOS end end |
