diff options
Diffstat (limited to 'spec/ruby/core/objectspace')
19 files changed, 585 insertions, 153 deletions
diff --git a/spec/ruby/core/objectspace/_id2ref_spec.rb b/spec/ruby/core/objectspace/_id2ref_spec.rb index c088ae2743..1ae3230bdf 100644 --- a/spec/ruby/core/objectspace/_id2ref_spec.rb +++ b/spec/ruby/core/objectspace/_id2ref_spec.rb @@ -1,52 +1,65 @@ require_relative '../../spec_helper' -describe "ObjectSpace._id2ref" do - it "converts an object id to a reference to the object" do - s = "I am a string" - r = ObjectSpace._id2ref(s.object_id) - r.should == s +ruby_version_is "4.0" do + describe "ObjectSpace._id2ref" do + it "is deprecated" do + id = nil.object_id + -> { + ObjectSpace._id2ref(id) + }.should complain(/warning: ObjectSpace\._id2ref is deprecated/) + end end +end - it "retrieves true by object_id" do - ObjectSpace._id2ref(true.object_id).should == true - end +ruby_version_is ""..."4.0" do + describe "ObjectSpace._id2ref" do + it "converts an object id to a reference to the object" do + s = "I am a string" + r = ObjectSpace._id2ref(s.object_id) + r.should == s + end - it "retrieves false by object_id" do - ObjectSpace._id2ref(false.object_id).should == false - end + it "retrieves true by object_id" do + ObjectSpace._id2ref(true.object_id).should == true + end - it "retrieves nil by object_id" do - ObjectSpace._id2ref(nil.object_id).should == nil - end + it "retrieves false by object_id" do + ObjectSpace._id2ref(false.object_id).should == false + end - it "retrieves a small Integer by object_id" do - ObjectSpace._id2ref(1.object_id).should == 1 - ObjectSpace._id2ref((-42).object_id).should == -42 - end + it "retrieves nil by object_id" do + ObjectSpace._id2ref(nil.object_id).should == nil + end - it "retrieves a large Integer by object_id" do - obj = 1 << 88 - ObjectSpace._id2ref(obj.object_id).should.equal?(obj) - end + it "retrieves a small Integer by object_id" do + ObjectSpace._id2ref(1.object_id).should == 1 + ObjectSpace._id2ref((-42).object_id).should == -42 + end - it "retrieves a Symbol by object_id" do - ObjectSpace._id2ref(:sym.object_id).should.equal?(:sym) - end + it "retrieves a large Integer by object_id" do + obj = 1 << 88 + ObjectSpace._id2ref(obj.object_id).should.equal?(obj) + end - it "retrieves a String by object_id" do - obj = "str" - ObjectSpace._id2ref(obj.object_id).should.equal?(obj) - end + it "retrieves a Symbol by object_id" do + ObjectSpace._id2ref(:sym.object_id).should.equal?(:sym) + end - it "retrieves a frozen literal String by object_id" do - ObjectSpace._id2ref("frozen string literal _id2ref".freeze.object_id).should.equal?("frozen string literal _id2ref".freeze) - end + it "retrieves a String by object_id" do + obj = "str" + ObjectSpace._id2ref(obj.object_id).should.equal?(obj) + end - it "retrieves an Encoding by object_id" do - ObjectSpace._id2ref(Encoding::UTF_8.object_id).should.equal?(Encoding::UTF_8) - end + it "retrieves a frozen literal String by object_id" do + ObjectSpace._id2ref("frozen string literal _id2ref".freeze.object_id).should.equal?("frozen string literal _id2ref".freeze) + end + + it "retrieves an Encoding by object_id" do + ObjectSpace._id2ref(Encoding::UTF_8.object_id).should.equal?(Encoding::UTF_8) + end - it 'raises RangeError when an object could not be found' do - proc { ObjectSpace._id2ref(1 << 60) }.should raise_error(RangeError) + it 'raises RangeError when an object could not be found' do + proc { ObjectSpace._id2ref(1 << 60) }.should raise_error(RangeError) + end end end diff --git a/spec/ruby/core/objectspace/add_finalizer_spec.rb b/spec/ruby/core/objectspace/add_finalizer_spec.rb deleted file mode 100644 index 3540ac0413..0000000000 --- a/spec/ruby/core/objectspace/add_finalizer_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative '../../spec_helper' - -describe "ObjectSpace.add_finalizer" do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/core/objectspace/call_finalizer_spec.rb b/spec/ruby/core/objectspace/call_finalizer_spec.rb deleted file mode 100644 index 6dce92ddd6..0000000000 --- a/spec/ruby/core/objectspace/call_finalizer_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative '../../spec_helper' - -describe "ObjectSpace.call_finalizer" do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb index 281785b0a4..0f4b54c345 100644 --- a/spec/ruby/core/objectspace/define_finalizer_spec.rb +++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb @@ -52,7 +52,7 @@ describe "ObjectSpace.define_finalizer" do Proc.new { puts "finalizer run" } end handler = scoped - obj = "Test" + obj = +"Test" ObjectSpace.define_finalizer(obj, handler) exit 0 RUBY @@ -60,60 +60,58 @@ describe "ObjectSpace.define_finalizer" do ruby_exe(code, :args => "2>&1").should include("finalizer run\n") end - ruby_version_is "3.0" do - it "warns if the finalizer has the object as the receiver" do - code = <<-RUBY - class CapturesSelf - def initialize - ObjectSpace.define_finalizer(self, proc { - puts "finalizer run" - }) - end + it "warns if the finalizer has the object as the receiver" do + code = <<-RUBY + class CapturesSelf + def initialize + ObjectSpace.define_finalizer(self, proc { + puts "finalizer run" + }) end - CapturesSelf.new - exit 0 - RUBY + end + CapturesSelf.new + exit 0 + RUBY - ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") - end + ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") + end - it "warns if the finalizer is a method bound to the receiver" do - code = <<-RUBY - class CapturesSelf - def initialize - ObjectSpace.define_finalizer(self, method(:finalize)) - end - def finalize(id) - puts "finalizer run" - end + it "warns if the finalizer is a method bound to the receiver" do + code = <<-RUBY + class CapturesSelf + def initialize + ObjectSpace.define_finalizer(self, method(:finalize)) end - CapturesSelf.new - exit 0 - RUBY + def finalize(id) + puts "finalizer run" + end + end + CapturesSelf.new + exit 0 + RUBY - ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") - end + ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") + end - it "warns if the finalizer was a block in the receiver" do - code = <<-RUBY - class CapturesSelf - def initialize - ObjectSpace.define_finalizer(self) do - puts "finalizer run" - end + it "warns if the finalizer was a block in the receiver" do + code = <<-RUBY + class CapturesSelf + def initialize + ObjectSpace.define_finalizer(self) do + puts "finalizer run" end end - CapturesSelf.new - exit 0 - RUBY + end + CapturesSelf.new + exit 0 + RUBY - ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") - end + ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") end it "calls a finalizer at exit even if it is self-referencing" do code = <<-RUBY - obj = "Test" + obj = +"Test" handler = Proc.new { puts "finalizer run" } ObjectSpace.define_finalizer(obj, handler) exit 0 @@ -143,9 +141,9 @@ describe "ObjectSpace.define_finalizer" do it "calls a finalizer defined in a finalizer running at exit" do code = <<-RUBY - obj = "Test" + obj = +"Test" handler = Proc.new do - obj2 = "Test" + obj2 = +"Test" handler2 = Proc.new { puts "finalizer 2 run" } ObjectSpace.define_finalizer(obj2, handler2) exit 0 @@ -158,7 +156,7 @@ describe "ObjectSpace.define_finalizer" do end it "allows multiple finalizers with different 'callables' to be defined" do - code = <<-RUBY + code = <<-'RUBY' obj = Object.new ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized1\n" }) @@ -169,4 +167,49 @@ describe "ObjectSpace.define_finalizer" do ruby_exe(code).lines.sort.should == ["finalized1\n", "finalized2\n"] end + + it "defines same finalizer only once" do + code = <<~RUBY + obj = Object.new + p = proc { |id| print "ok" } + ObjectSpace.define_finalizer(obj, p.dup) + ObjectSpace.define_finalizer(obj, p.dup) + RUBY + + ruby_exe(code).should == "ok" + end + + it "returns the defined finalizer" do + obj = Object.new + p = proc { |id| } + p2 = p.dup + + ret = ObjectSpace.define_finalizer(obj, p) + ret.should == [0, p] + ret[1].should.equal?(p) + + ret = ObjectSpace.define_finalizer(obj, p2) + ret.should == [0, p] + ret[1].should.equal?(p) + end + + describe "when $VERBOSE is not nil" do + it "warns if an exception is raised in finalizer" do + code = <<-RUBY + ObjectSpace.define_finalizer(Object.new) { raise "finalizing" } + RUBY + + ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing") + end + end + + describe "when $VERBOSE is nil" do + it "does not warn even if an exception is raised in finalizer" do + code = <<-RUBY + ObjectSpace.define_finalizer(Object.new) { raise "finalizing" } + RUBY + + ruby_exe(code, args: "2>&1", options: "-W0").should == "" + end + end end diff --git a/spec/ruby/core/objectspace/finalizers_spec.rb b/spec/ruby/core/objectspace/finalizers_spec.rb deleted file mode 100644 index e7f20fc8a0..0000000000 --- a/spec/ruby/core/objectspace/finalizers_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative '../../spec_helper' - -describe "ObjectSpace.finalizers" do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/core/objectspace/garbage_collect_spec.rb b/spec/ruby/core/objectspace/garbage_collect_spec.rb index 1aec3ea072..521eaa8785 100644 --- a/spec/ruby/core/objectspace/garbage_collect_spec.rb +++ b/spec/ruby/core/objectspace/garbage_collect_spec.rb @@ -6,8 +6,8 @@ describe "ObjectSpace.garbage_collect" do -> { ObjectSpace.garbage_collect }.should_not raise_error end - it "doesn't accept any arguments" do - -> { ObjectSpace.garbage_collect(1) }.should raise_error(ArgumentError) + it "accepts keyword arguments" do + ObjectSpace.garbage_collect(full_mark: true, immediate_sweep: true).should == nil end it "ignores the supplied block" do diff --git a/spec/ruby/core/objectspace/remove_finalizer_spec.rb b/spec/ruby/core/objectspace/remove_finalizer_spec.rb deleted file mode 100644 index 0b2b8cf16b..0000000000 --- a/spec/ruby/core/objectspace/remove_finalizer_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative '../../spec_helper' - -describe "ObjectSpace.remove_finalizer" do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/core/objectspace/undefine_finalizer_spec.rb b/spec/ruby/core/objectspace/undefine_finalizer_spec.rb index 11d43121f8..f57d5a7845 100644 --- a/spec/ruby/core/objectspace/undefine_finalizer_spec.rb +++ b/spec/ruby/core/objectspace/undefine_finalizer_spec.rb @@ -1,5 +1,33 @@ require_relative '../../spec_helper' describe "ObjectSpace.undefine_finalizer" do - it "needs to be reviewed for spec completeness" + it "removes finalizers for an object" do + code = <<~RUBY + obj = Object.new + ObjectSpace.define_finalizer(obj, proc { |id| puts "hello" }) + ObjectSpace.undefine_finalizer(obj) + RUBY + + ruby_exe(code).should.empty? + end + + it "should not remove finalizers for a frozen object" do + code = <<~RUBY + obj = Object.new + ObjectSpace.define_finalizer(obj, proc { |id| print "ok" }) + obj.freeze + begin + ObjectSpace.undefine_finalizer(obj) + rescue + end + RUBY + + ruby_exe(code).should == "ok" + end + + it "should raise when removing finalizers for a frozen object" do + obj = Object.new + obj.freeze + -> { ObjectSpace.undefine_finalizer(obj) }.should raise_error(FrozenError) + end end diff --git a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb new file mode 100644 index 0000000000..8050e2c307 --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../../spec_helper' + +ruby_version_is '3.3' do + describe "ObjectSpace::WeakKeyMap#clear" do + it "removes all the entries" do + m = ObjectSpace::WeakKeyMap.new + + key = Object.new + value = Object.new + m[key] = value + + key2 = Object.new + value2 = Object.new + m[key2] = value2 + + m.clear + + m.key?(key).should == false + m.key?(key2).should == false + end + + it "returns self" do + m = ObjectSpace::WeakKeyMap.new + m.clear.should.equal?(m) + end + end +end diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb new file mode 100644 index 0000000000..3cd61355d6 --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb @@ -0,0 +1,51 @@ +require_relative '../../../spec_helper' + +ruby_version_is '3.3' do + describe "ObjectSpace::WeakKeyMap#delete" do + it "removes the entry and returns the deleted value" do + m = ObjectSpace::WeakKeyMap.new + key = Object.new + value = Object.new + m[key] = value + + m.delete(key).should == value + m.key?(key).should == false + end + + it "uses equality semantic" do + m = ObjectSpace::WeakKeyMap.new + key = "foo".upcase + value = Object.new + m[key] = value + + m.delete("foo".upcase).should == value + m.key?(key).should == false + end + + it "calls supplied block if the key is not found" do + key = Object.new + m = ObjectSpace::WeakKeyMap.new + return_value = m.delete(key) do |yielded_key| + yielded_key.should == key + 5 + end + return_value.should == 5 + end + + it "returns nil if the key is not found when no block is given" do + m = ObjectSpace::WeakKeyMap.new + m.delete(Object.new).should == nil + end + + it "returns nil when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new + + map.delete(1).should == nil + map.delete(1.0).should == nil + map.delete(:a).should == nil + map.delete(true).should == nil + map.delete(false).should == nil + map.delete(nil).should == nil + end + end +end diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb new file mode 100644 index 0000000000..51368e8d3b --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb @@ -0,0 +1,107 @@ +require_relative '../../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.3" do + describe "ObjectSpace::WeakKeyMap#[]" do + it "is faithful to the map's content" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a b].map(&:upcase) + ref1, ref2 = %w[x y] + map[key1] = ref1 + map[key1].should == ref1 + map[key1] = ref1 + map[key1].should == ref1 + map[key2] = ref2 + map[key1].should == ref1 + map[key2].should == ref2 + end + + it "compares keys with #eql? semantics" do + map = ObjectSpace::WeakKeyMap.new + key = [1.0] + map[key] = "x" + map[[1]].should == nil + map[[1.0]].should == "x" + key.should == [1.0] # keep the key alive until here to keep the map entry + + map = ObjectSpace::WeakKeyMap.new + key = [1] + map[key] = "x" + map[[1.0]].should == nil + map[[1]].should == "x" + key.should == [1] # keep the key alive until here to keep the map entry + + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a a].map(&:upcase) + ref = "x" + map[key1] = ref + map[key2].should == ref + end + + it "compares key via #hash first" do + x = mock('0') + x.should_receive(:hash).and_return(0) + + map = ObjectSpace::WeakKeyMap.new + key = 'foo' + map[key] = :bar + map[x].should == nil + end + + it "does not compare keys with different #hash values via #eql?" do + x = mock('x') + x.should_not_receive(:eql?) + x.stub!(:hash).and_return(0) + + y = mock('y') + y.should_not_receive(:eql?) + y.stub!(:hash).and_return(1) + + map = ObjectSpace::WeakKeyMap.new + map[y] = 1 + map[x].should == nil + end + + it "compares keys with the same #hash value via #eql?" do + x = mock('x') + x.should_receive(:eql?).and_return(true) + x.stub!(:hash).and_return(42) + + y = mock('y') + y.should_not_receive(:eql?) + y.stub!(:hash).and_return(42) + + map = ObjectSpace::WeakKeyMap.new + map[y] = 1 + map[x].should == 1 + end + + it "finds a value via an identical key even when its #eql? isn't reflexive" do + x = mock('x') + x.should_receive(:hash).at_least(1).and_return(42) + x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. + + map = ObjectSpace::WeakKeyMap.new + map[x] = :x + map[x].should == :x + end + + it "supports keys with private #hash method" do + key = WeakKeyMapSpecs::KeyWithPrivateHash.new + map = ObjectSpace::WeakKeyMap.new + map[key] = 42 + map[key].should == 42 + end + + it "returns nil and does not raise error when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new + + map[1].should == nil + map[1.0].should == nil + map[:a].should == nil + map[true].should == nil + map[false].should == nil + map[nil].should == nil + end + end +end diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb new file mode 100644 index 0000000000..8db8d780c7 --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb @@ -0,0 +1,82 @@ +require_relative '../../../spec_helper' + +ruby_version_is "3.3" do + describe "ObjectSpace::WeakKeyMap#[]=" do + def should_accept(map, key, value) + (map[key] = value).should == value + map.should.key?(key) + map[key].should == value + end + + it "is correct" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a b].map(&:upcase) + ref1, ref2 = %w[x y] + should_accept(map, key1, ref1) + should_accept(map, key1, ref1) + should_accept(map, key2, ref2) + map[key1].should == ref1 + end + + it "requires the keys to implement #hash" do + map = ObjectSpace::WeakKeyMap.new + -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/) + end + + it "accepts frozen keys or values" do + map = ObjectSpace::WeakKeyMap.new + x = Object.new + should_accept(map, x, true) + should_accept(map, x, false) + should_accept(map, x, 42) + should_accept(map, x, :foo) + + y = Object.new.freeze + should_accept(map, x, y) + should_accept(map, y, x) + end + + it "does not duplicate and freeze String keys (like Hash#[]= does)" do + map = ObjectSpace::WeakKeyMap.new + key = +"a" + map[key] = 1 + + map.getkey("a").should.equal? key + map.getkey("a").should_not.frozen? + + key.should == "a" # keep the key alive until here to keep the map entry + end + + context "a key cannot be garbage collected" do + it "raises ArgumentError when Integer is used as a key" do + map = ObjectSpace::WeakKeyMap.new + -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) + end + + it "raises ArgumentError when Float is used as a key" do + map = ObjectSpace::WeakKeyMap.new + -> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) + end + + it "raises ArgumentError when Symbol is used as a key" do + map = ObjectSpace::WeakKeyMap.new + -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) + end + + it "raises ArgumentError when true is used as a key" do + map = ObjectSpace::WeakKeyMap.new + -> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) + end + + it "raises ArgumentError when false is used as a key" do + map = ObjectSpace::WeakKeyMap.new + -> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) + end + + it "raises ArgumentError when nil is used as a key" do + map = ObjectSpace::WeakKeyMap.new + -> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/) + end + end + end +end diff --git a/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb b/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb new file mode 100644 index 0000000000..0fd04551b5 --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb @@ -0,0 +1,5 @@ +module WeakKeyMapSpecs + class KeyWithPrivateHash + private :hash + end +end diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb new file mode 100644 index 0000000000..8a2dbf809d --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../../spec_helper' + +ruby_version_is "3.3" do + describe "ObjectSpace::WeakKeyMap#getkey" do + it "returns the existing equal key" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a a].map(&:upcase) + + map[key1] = true + map.getkey(key2).should equal(key1) + map.getkey("X").should == nil + + key1.should == "A" # keep the key alive until here to keep the map entry + key2.should == "A" # keep the key alive until here to keep the map entry + end + + it "returns nil when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new + + map.getkey(1).should == nil + map.getkey(1.0).should == nil + map.getkey(:a).should == nil + map.getkey(true).should == nil + map.getkey(false).should == nil + map.getkey(nil).should == nil + end + end +end diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb new file mode 100644 index 0000000000..319f050970 --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' + +ruby_version_is "3.3" do + describe "ObjectSpace::WeakKeyMap#inspect" do + it "only displays size in output" do + map = ObjectSpace::WeakKeyMap.new + key1, key2, key3 = "foo", "bar", "bar" + map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=0>\z/ + map[key1] = 1 + map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=1>\z/ + map[key2] = 2 + map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ + map[key3] = 3 + map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ + + key1.should == "foo" # keep the key alive until here to keep the map entry + key2.should == "bar" # keep the key alive until here to keep the map entry + key3.should == "bar" # keep the key alive until here to keep the map entry + end + end +end diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb new file mode 100644 index 0000000000..a9a2e12432 --- /dev/null +++ b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb @@ -0,0 +1,44 @@ +require_relative '../../../spec_helper' + +ruby_version_is "3.3" do + describe "ObjectSpace::WeakKeyMap#key?" do + it "recognizes keys in use" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a b].map(&:upcase) + ref1, ref2 = %w[x y] + + map[key1] = ref1 + map.key?(key1).should == true + map[key1] = ref1 + map.key?(key1).should == true + map[key2] = ref2 + map.key?(key2).should == true + end + + it "matches using equality semantics" do + map = ObjectSpace::WeakKeyMap.new + key1, key2 = %w[a a].map(&:upcase) + ref = "x" + map[key1] = ref + map.key?(key2).should == true + end + + it "reports true if the pair exists and the value is nil" do + map = ObjectSpace::WeakKeyMap.new + key = Object.new + map[key] = nil + map.key?(key).should == true + end + + it "returns false when a key cannot be garbage collected" do + map = ObjectSpace::WeakKeyMap.new + + map.key?(1).should == false + map.key?(1.0).should == false + map.key?(:a).should == false + map.key?(true).should == false + map.key?(false).should == false + map.key?(nil).should == false + end + end +end diff --git a/spec/ruby/core/objectspace/weakmap/delete_spec.rb b/spec/ruby/core/objectspace/weakmap/delete_spec.rb new file mode 100644 index 0000000000..302de264fb --- /dev/null +++ b/spec/ruby/core/objectspace/weakmap/delete_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../../spec_helper' + +ruby_version_is '3.3' do + describe "ObjectSpace::WeakMap#delete" do + it "removes the entry and returns the deleted value" do + m = ObjectSpace::WeakMap.new + key = Object.new + value = Object.new + m[key] = value + + m.delete(key).should == value + m.key?(key).should == false + end + + it "calls supplied block if the key is not found" do + key = Object.new + m = ObjectSpace::WeakMap.new + return_value = m.delete(key) do |yielded_key| + yielded_key.should == key + 5 + end + return_value.should == 5 + end + + it "returns nil if the key is not found when no block is given" do + m = ObjectSpace::WeakMap.new + m.delete(Object.new).should == nil + end + end +end diff --git a/spec/ruby/core/objectspace/weakmap/element_set_spec.rb b/spec/ruby/core/objectspace/weakmap/element_set_spec.rb index 2b53650148..8588877158 100644 --- a/spec/ruby/core/objectspace/weakmap/element_set_spec.rb +++ b/spec/ruby/core/objectspace/weakmap/element_set_spec.rb @@ -17,45 +17,22 @@ describe "ObjectSpace::WeakMap#[]=" do map[key1].should == ref1 end - ruby_version_is ""..."2.7" do - it "does not accept primitive or frozen keys or values" do - map = ObjectSpace::WeakMap.new - x = Object.new - -> { map[true] = x }.should raise_error(ArgumentError) - -> { map[false] = x }.should raise_error(ArgumentError) - -> { map[nil] = x }.should raise_error(ArgumentError) - -> { map[42] = x }.should raise_error(ArgumentError) - -> { map[:foo] = x }.should raise_error(ArgumentError) - -> { map[x] = true }.should raise_error(ArgumentError) - -> { map[x] = false }.should raise_error(ArgumentError) - -> { map[x] = nil }.should raise_error(ArgumentError) - -> { map[x] = 42 }.should raise_error(ArgumentError) - -> { map[x] = :foo }.should raise_error(ArgumentError) - - y = Object.new.freeze - -> { map[x] = y}.should raise_error(FrozenError) - -> { map[y] = x}.should raise_error(FrozenError) - end - end - - ruby_version_is "2.7" do - it "accepts primitive or frozen keys or values" do - map = ObjectSpace::WeakMap.new - x = Object.new - should_accept(map, true, x) - should_accept(map, false, x) - should_accept(map, nil, x) - should_accept(map, 42, x) - should_accept(map, :foo, x) + it "accepts primitive or frozen keys or values" do + map = ObjectSpace::WeakMap.new + x = Object.new + should_accept(map, true, x) + should_accept(map, false, x) + should_accept(map, nil, x) + should_accept(map, 42, x) + should_accept(map, :foo, x) - should_accept(map, x, true) - should_accept(map, x, false) - should_accept(map, x, 42) - should_accept(map, x, :foo) + should_accept(map, x, true) + should_accept(map, x, false) + should_accept(map, x, 42) + should_accept(map, x, :foo) - y = Object.new.freeze - should_accept(map, x, y) - should_accept(map, y, x) - end + y = Object.new.freeze + should_accept(map, x, y) + should_accept(map, y, x) end end diff --git a/spec/ruby/core/objectspace/weakmap/shared/include.rb b/spec/ruby/core/objectspace/weakmap/shared/include.rb index f9c174b6d1..1770eeac8b 100644 --- a/spec/ruby/core/objectspace/weakmap/shared/include.rb +++ b/spec/ruby/core/objectspace/weakmap/shared/include.rb @@ -20,15 +20,11 @@ describe :weakmap_include?, shared: true do map.send(@method, key2).should == false end - ruby_version_is "2.7" do - ruby_bug "#16826", "2.7.0"..."2.7.2" do - it "reports true if the pair exists and the value is nil" do - map = ObjectSpace::WeakMap.new - key = Object.new - map[key] = nil - map.size.should == 1 - map.send(@method, key).should == true - end - end + it "reports true if the pair exists and the value is nil" do + map = ObjectSpace::WeakMap.new + key = Object.new + map[key] = nil + map.size.should == 1 + map.send(@method, key).should == true end end |
