ruby/test/ruby/test_object_id.rb
Jean Boussier 4eeec614bb shapes: Rename TOO_COMPLEX in just COMPLEX
The `too_` prefix wasn't consistently used and just make the
thing longer for no benefit.
2026-05-06 10:10:16 +02:00

304 lines
7.1 KiB
Ruby

require 'test/unit'
require "securerandom"
class TestObjectId < Test::Unit::TestCase
def setup
@obj = Object.new
end
def test_dup_new_id
id = @obj.object_id
refute_equal id, @obj.dup.object_id
end
def test_dup_with_ivar_and_id
id = @obj.object_id
@obj.instance_variable_set(:@foo, 42)
copy = @obj.dup
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
end
def test_dup_with_id_and_ivar
@obj.instance_variable_set(:@foo, 42)
id = @obj.object_id
copy = @obj.dup
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
end
def test_dup_with_id_and_ivar_and_frozen
@obj.instance_variable_set(:@foo, 42)
@obj.freeze
id = @obj.object_id
copy = @obj.dup
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
refute_predicate copy, :frozen?
end
def test_clone_new_id
id = @obj.object_id
refute_equal id, @obj.clone.object_id
end
def test_clone_with_ivar_and_id
id = @obj.object_id
@obj.instance_variable_set(:@foo, 42)
copy = @obj.clone
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
end
def test_clone_with_id_and_ivar
@obj.instance_variable_set(:@foo, 42)
id = @obj.object_id
copy = @obj.clone
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
end
def test_clone_with_id_and_ivar_and_frozen
@obj.instance_variable_set(:@foo, 42)
@obj.freeze
id = @obj.object_id
copy = @obj.clone
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
assert_predicate copy, :frozen?
end
def test_marshal_new_id
return pass if @obj.is_a?(Module)
id = @obj.object_id
refute_equal id, Marshal.load(Marshal.dump(@obj)).object_id
end
def test_marshal_with_ivar_and_id
return pass if @obj.is_a?(Module)
id = @obj.object_id
@obj.instance_variable_set(:@foo, 42)
copy = Marshal.load(Marshal.dump(@obj))
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
end
def test_marshal_with_id_and_ivar
return pass if @obj.is_a?(Module)
@obj.instance_variable_set(:@foo, 42)
id = @obj.object_id
copy = Marshal.load(Marshal.dump(@obj))
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
end
def test_marshal_with_id_and_ivar_and_frozen
return pass if @obj.is_a?(Module)
@obj.instance_variable_set(:@foo, 42)
@obj.freeze
id = @obj.object_id
copy = Marshal.load(Marshal.dump(@obj))
refute_equal id, copy.object_id
assert_equal 42, copy.instance_variable_get(:@foo)
refute_predicate copy, :frozen?
end
def test_object_id_need_resize
(3 - @obj.instance_variables.size).times do |i|
@obj.instance_variable_set("@a_#{i}", "[Bug #21445]")
end
@obj.object_id
GC.start
end
end
class TestObjectIdClass < TestObjectId
def setup
@obj = Class.new
end
end
class TestObjectIdGeneric < TestObjectId
def setup
@obj = Array.new
end
end
class TestObjectIdTooComplex < TestObjectId
class TooComplex
def initialize
@complex_obj_id_test = 1
end
end
def setup
if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
end
8.times do |i|
TooComplex.new.instance_variable_set("@TestObjectIdTooComplex#{i}", 1)
end
@obj = TooComplex.new
@obj.instance_variable_set("@a#{rand(10_000)}", 1)
if defined?(RubyVM::Shape)
assert_predicate(RubyVM::Shape.of(@obj), :complex?)
end
end
end
class TestObjectIdTooComplexClass < TestObjectId
class TooComplex < Module
end
def setup
if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
end
@obj = TooComplex.new
@obj.instance_variable_set("@___#{SecureRandom.hex}", 1)
8.times do |i|
@obj.instance_variable_set("@TestObjectIdTooComplexClass#{i}", 1)
@obj.remove_instance_variable("@TestObjectIdTooComplexClass#{i}")
end
@obj.instance_variable_set("@test", 1)
if defined?(RubyVM::Shape)
assert_predicate(RubyVM::Shape.of(@obj), :complex?)
end
end
end
class TestObjectIdTooComplexGeneric < TestObjectId
class TooComplex < Array
end
def setup
if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
end
8.times do |i|
TooComplex.new.instance_variable_set("@TestObjectIdTooComplexGeneric#{i}", 1)
end
@obj = TooComplex.new
@obj.instance_variable_set("@a#{rand(10_000)}", 1)
@obj.instance_variable_set("@a#{rand(10_000)}", 1)
if defined?(RubyVM::Shape)
assert_predicate(RubyVM::Shape.of(@obj), :complex?)
end
end
end
class TestObjectIdRactor < Test::Unit::TestCase
def test_object_id_race_free
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
Warning[:experimental] = false
class MyClass
attr_reader :a, :b, :c
def initialize
@a = @b = @c = nil
end
end
N = 10_000
objs = Ractor.make_shareable(N.times.map { MyClass.new })
results = 4.times.map{
Ractor.new(objs) { |objs|
vars = []
ids = []
objs.each do |obj|
vars << obj.a << obj.b << obj.c
ids << obj.object_id
end
[vars, ids]
}
}.map(&:value)
assert_equal 1, results.uniq.size
end;
end
def test_external_object_id_ractor_move
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
Warning[:experimental] = false
class MyClass
attr_reader :a, :b, :c
def initialize
@a = @b = @c = nil
end
end
obj = Ractor.make_shareable(MyClass.new)
object_id = obj.object_id
obj = Ractor.new { Ractor.receive }.send(obj, move: true).value
assert_equal object_id, obj.object_id
end;
end
end
class TestObjectIdStruct < TestObjectId
EmbeddedStruct = Struct.new(:embedded_field)
def setup
@obj = EmbeddedStruct.new
end
end
class TestObjectIdStructGenIvar < TestObjectId
GenIvarStruct = Struct.new(:a, :b, :c)
def setup
@obj = GenIvarStruct.new
end
end
class TestObjectIdStructNotEmbed < TestObjectId
MANY_IVS = 80
StructNotEmbed = Struct.new(*MANY_IVS.times.map { |i| :"field_#{i}" })
def setup
@obj = StructNotEmbed.new
end
end
class TestObjectIdStructTooComplex < TestObjectId
StructTooComplex = Struct.new(:a) do
def initialize
@complex_obj_id_test = 1
end
end
def setup
if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
end
8.times do |i|
StructTooComplex.new.instance_variable_set("@TestObjectIdStructTooComplex#{i}", 1)
end
@obj = StructTooComplex.new
@obj.instance_variable_set("@a#{rand(10_000)}", 1)
if defined?(RubyVM::Shape)
assert_predicate(RubyVM::Shape.of(@obj), :complex?)
end
end
end