1# frozen_string_literal: false 2require 'test/unit' 3 4class TestObjectSpace < Test::Unit::TestCase 5 def self.deftest_id2ref(obj) 6 /:(\d+)/ =~ caller[0] 7 file = $` 8 line = $1.to_i 9 code = <<"End" 10 define_method("test_id2ref_#{line}") {\ 11 o = ObjectSpace._id2ref(obj.object_id);\ 12 assert_same(obj, o, "didn't round trip: \#{obj.inspect}");\ 13 } 14End 15 eval code, binding, file, line 16 end 17 18 deftest_id2ref(-0x4000000000000001) 19 deftest_id2ref(-0x4000000000000000) 20 deftest_id2ref(-0x40000001) 21 deftest_id2ref(-0x40000000) 22 deftest_id2ref(-1) 23 deftest_id2ref(0) 24 deftest_id2ref(1) 25 deftest_id2ref(0x3fffffff) 26 deftest_id2ref(0x40000000) 27 deftest_id2ref(0x3fffffffffffffff) 28 deftest_id2ref(0x4000000000000000) 29 deftest_id2ref(:a) 30 deftest_id2ref(:abcdefghijilkjl) 31 deftest_id2ref(:==) 32 deftest_id2ref(Object.new) 33 deftest_id2ref(self) 34 deftest_id2ref(true) 35 deftest_id2ref(false) 36 deftest_id2ref(nil) 37 38 def test_count_objects 39 h = {} 40 ObjectSpace.count_objects(h) 41 assert_kind_of(Hash, h) 42 assert_empty(h.keys.delete_if {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) 43 assert_empty(h.values.delete_if {|x| x.is_a?(Integer) }) 44 45 h = ObjectSpace.count_objects 46 assert_kind_of(Hash, h) 47 assert_empty(h.keys.delete_if {|x| x.is_a?(Symbol) || x.is_a?(Integer) }) 48 assert_empty(h.values.delete_if {|x| x.is_a?(Integer) }) 49 50 assert_raise(TypeError) { ObjectSpace.count_objects(1) } 51 52 h0 = {:T_FOO=>1000} 53 h = ObjectSpace.count_objects(h0) 54 assert_same(h0, h) 55 assert_equal(0, h0[:T_FOO]) 56 end 57 58 def test_finalizer 59 assert_in_out_err(["-e", <<-END], "", %w(:ok :ok :ok :ok), []) 60 a = [] 61 ObjectSpace.define_finalizer(a) { p :ok } 62 b = a.dup 63 ObjectSpace.define_finalizer(a) { p :ok } 64 !b 65 END 66 assert_raise(ArgumentError) { ObjectSpace.define_finalizer([], Object.new) } 67 68 code = proc do |priv| 69 <<-"CODE" 70 fin = Object.new 71 class << fin 72 #{priv}def call(id) 73 puts "finalized" 74 end 75 end 76 ObjectSpace.define_finalizer([], fin) 77 CODE 78 end 79 assert_in_out_err([], code[""], ["finalized"]) 80 assert_in_out_err([], code["private "], ["finalized"]) 81 c = EnvUtil.labeled_class("C\u{3042}").new 82 o = Object.new 83 assert_raise_with_message(ArgumentError, /C\u{3042}/) { 84 ObjectSpace.define_finalizer(o, c) 85 } 86 end 87 88 def test_finalizer_with_super 89 assert_in_out_err(["-e", <<-END], "", %w(:ok), []) 90 class A 91 def foo 92 end 93 end 94 95 class B < A 96 def foo 97 1.times { super } 98 end 99 end 100 101 class C 102 module M 103 end 104 105 FINALIZER = proc do 106 M.module_eval(__FILE__, "", __LINE__) do 107 end 108 end 109 110 def define_finalizer 111 ObjectSpace.define_finalizer(self, FINALIZER) 112 end 113 end 114 115 class D 116 def foo 117 B.new.foo 118 end 119 end 120 121 C::M.singleton_class.send :define_method, :module_eval do |src, id, line| 122 end 123 124 GC.stress = true 125 10.times do 126 C.new.define_finalizer 127 D.new.foo 128 end 129 130 p :ok 131 END 132 end 133 134 def test_each_object 135 klass = Class.new 136 new_obj = klass.new 137 138 found = [] 139 count = ObjectSpace.each_object(klass) do |obj| 140 found << obj 141 end 142 assert_equal(1, count) 143 assert_equal(1, found.size) 144 assert_same(new_obj, found[0]) 145 end 146 147 def test_each_object_enumerator 148 klass = Class.new 149 new_obj = klass.new 150 151 found = [] 152 counter = ObjectSpace.each_object(klass) 153 assert_equal(1, counter.each {|obj| found << obj}) 154 assert_equal(1, found.size) 155 assert_same(new_obj, found[0]) 156 end 157 158 def test_each_object_no_gabage 159 assert_separately([], <<-End) 160 GC.disable 161 eval('begin; 1.times{}; rescue; ensure; end') 162 arys = [] 163 ObjectSpace.each_object(Array){|ary| 164 arys << ary 165 } 166 GC.enable 167 arys.each{|ary| 168 begin 169 assert_equal(String, ary.inspect.class) # should not cause SEGV 170 rescue RuntimeError 171 # rescue "can't modify frozen File" error. 172 end 173 } 174 End 175 end 176 177 def test_each_object_recursive_key 178 assert_normal_exit(<<-'end;', '[ruby-core:66742] [Bug #10579]') 179 h = {["foo"]=>nil} 180 p Thread.current[:__recursive_key__] 181 end; 182 end 183 184 def test_each_object_singleton_class 185 assert_separately([], <<-End) 186 class C 187 class << self 188 $c = self 189 end 190 end 191 192 exist = false 193 ObjectSpace.each_object(Class){|o| 194 exist = true if $c == o 195 } 196 assert(exist, 'Bug #11360') 197 End 198 199 klass = Class.new 200 instance = klass.new 201 sclass = instance.singleton_class 202 meta = klass.singleton_class 203 assert_kind_of(meta, sclass) 204 assert_include(ObjectSpace.each_object(meta).to_a, sclass) 205 end 206end 207