Fix crash during compaction
[ruby.git] / test / ruby / test_weakmap.rb
blob9bbe2d6b81737bd48230d12633cf70c270261904
1 # frozen_string_literal: false
2 require 'test/unit'
4 class TestWeakMap < Test::Unit::TestCase
5   def setup
6     @wm = ObjectSpace::WeakMap.new
7   end
9   def test_map
10     x = Object.new
11     k = "foo"
12     @wm[k] = x
13     assert_same(x, @wm[k])
14     assert_not_same(x, @wm["FOO".downcase])
15   end
17   def test_aset_const
18     x = Object.new
19     @wm[true] = x
20     assert_same(x, @wm[true])
21     @wm[false] = x
22     assert_same(x, @wm[false])
23     @wm[nil] = x
24     assert_same(x, @wm[nil])
25     @wm[42] = x
26     assert_same(x, @wm[42])
27     @wm[:foo] = x
28     assert_same(x, @wm[:foo])
30     @wm[x] = true
31     assert_same(true, @wm[x])
32     @wm[x] = false
33     assert_same(false, @wm[x])
34     @wm[x] = nil
35     assert_same(nil, @wm[x])
36     @wm[x] = 42
37     assert_same(42, @wm[x])
38     @wm[x] = :foo
39     assert_same(:foo, @wm[x])
40   end
42   def assert_weak_include(m, k, n = 100)
43     if n > 0
44       return assert_weak_include(m, k, n-1)
45     end
46     1.times do
47       x = Object.new
48       @wm[k] = x
49       assert_send([@wm, m, k])
50       assert_not_send([@wm, m, "FOO".downcase])
51       x = Object.new
52     end
53   end
55   def test_include?
56     m = __callee__[/test_(.*)/, 1]
57     k = "foo"
58     1.times do
59       assert_weak_include(m, k)
60     end
61     GC.start
62     pend('TODO: failure introduced from 837fd5e494731d7d44786f29e7d6e8c27029806f')
63     assert_not_send([@wm, m, k])
64   end
65   alias test_member? test_include?
66   alias test_key? test_include?
68   def test_inspect
69     x = Object.new
70     k = BasicObject.new
71     @wm[k] = x
72     assert_match(/\A\#<#{@wm.class.name}:[^:]+:\s\#<BasicObject:[^:]*>\s=>\s\#<Object:[^:]*>>\z/,
73                  @wm.inspect)
74   end
76   def test_inspect_garbage
77     1000.times do |i|
78       @wm[i] = Object.new
79       @wm.inspect
80     end
81     assert_match(/\A\#<#{@wm.class.name}:[^:]++:(?:\s\d+\s=>\s\#<(?:Object|collected):[^:<>]*+>(?:,|>\z))+/,
82                  @wm.inspect)
83   end
85   def test_each
86     m = __callee__[/test_(.*)/, 1]
87     x1 = Object.new
88     k1 = "foo"
89     @wm[k1] = x1
90     x2 = Object.new
91     k2 = "bar"
92     @wm[k2] = x2
93     n = 0
94     @wm.__send__(m) do |k, v|
95       assert_match(/\A(?:foo|bar)\z/, k)
96       case k
97       when /foo/
98         assert_same(k1, k)
99         assert_same(x1, v)
100       when /bar/
101         assert_same(k2, k)
102         assert_same(x2, v)
103       end
104       n += 1
105     end
106     assert_equal(2, n)
107   end
109   def test_each_key
110     x1 = Object.new
111     k1 = "foo"
112     @wm[k1] = x1
113     x2 = Object.new
114     k2 = "bar"
115     @wm[k2] = x2
116     n = 0
117     @wm.each_key do |k|
118       assert_match(/\A(?:foo|bar)\z/, k)
119       case k
120       when /foo/
121         assert_same(k1, k)
122       when /bar/
123         assert_same(k2, k)
124       end
125       n += 1
126     end
127     assert_equal(2, n)
128   end
130   def test_each_value
131     x1 = "foo"
132     k1 = Object.new
133     @wm[k1] = x1
134     x2 = "bar"
135     k2 = Object.new
136     @wm[k2] = x2
137     n = 0
138     @wm.each_value do |v|
139       assert_match(/\A(?:foo|bar)\z/, v)
140       case v
141       when /foo/
142         assert_same(x1, v)
143       when /bar/
144         assert_same(x2, v)
145       end
146       n += 1
147     end
148     assert_equal(2, n)
149   end
151   def test_size
152     m = __callee__[/test_(.*)/, 1]
153     assert_equal(0, @wm.__send__(m))
154     x1 = "foo"
155     k1 = Object.new
156     @wm[k1] = x1
157     assert_equal(1, @wm.__send__(m))
158     x2 = "bar"
159     k2 = Object.new
160     @wm[k2] = x2
161     assert_equal(2, @wm.__send__(m))
162   end
163   alias test_length test_size
165   def test_frozen_object
166     o = Object.new.freeze
167     assert_nothing_raised(FrozenError) {@wm[o] = 'foo'}
168     assert_nothing_raised(FrozenError) {@wm['foo'] = o}
169   end
171   def test_no_memory_leak
172     assert_no_memory_leak([], '', "#{<<~"begin;"}\n#{<<~'end;'}", "[Bug #19398]", rss: true, limit: 1.5, timeout: 60)
173     begin;
174       1_000_000.times do
175         ObjectSpace::WeakMap.new
176       end
177     end;
178   end
180   def test_compaction_bug_19529
181     obj = Object.new
182     100.times do |i|
183       GC.compact
184       @wm[i] = obj
185     end
187     assert_separately(%w(--disable-gems), <<-'end;')
188       wm = ObjectSpace::WeakMap.new
189       obj = Object.new
190       100.times do
191         wm[Object.new] = obj
192         GC.start
193       end
194       GC.compact
195     end;
196   end