aboutsummaryrefslogtreecommitdiffstats
path: root/spec/ruby/core/objectspace/define_finalizer_spec.rb
diff options
context:
space:
mode:
authoreregon <eregon@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-09-20 20:18:52 +0000
committereregon <eregon@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-09-20 20:18:52 +0000
commit1d15d5f08032acf1b7bceacbb450d617ff6e0931 (patch)
treea3785a79899302bc149e4a6e72f624ac27dc1f10 /spec/ruby/core/objectspace/define_finalizer_spec.rb
parent75bfc6440d595bf339007f4fb280fd4d743e89c1 (diff)
downloadruby-1d15d5f08032acf1b7bceacbb450d617ff6e0931.tar.gz
Move spec/rubyspec to spec/ruby for consistency
* Other ruby implementations use the spec/ruby directory. [Misc #13792] [ruby-core:82287] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59979 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'spec/ruby/core/objectspace/define_finalizer_spec.rb')
-rw-r--r--spec/ruby/core/objectspace/define_finalizer_spec.rb101
1 files changed, 101 insertions, 0 deletions
diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb
new file mode 100644
index 0000000000..969e8b16b0
--- /dev/null
+++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb
@@ -0,0 +1,101 @@
+require File.expand_path('../../../spec_helper', __FILE__)
+require File.expand_path('../fixtures/classes', __FILE__)
+
+# NOTE: A call to define_finalizer does not guarantee that the
+# passed proc or callable will be called at any particular time.
+# It is highly questionable whether these aspects of ObjectSpace
+# should be spec'd at all.
+describe "ObjectSpace.define_finalizer" do
+ it "raises an ArgumentError if the action does not respond to call" do
+ lambda {
+ ObjectSpace.define_finalizer("", mock("ObjectSpace.define_finalizer no #call"))
+ }.should raise_error(ArgumentError)
+ end
+
+ it "accepts an object and a proc" do
+ handler = lambda { |obj| obj }
+ ObjectSpace.define_finalizer("garbage", handler).should == [0, handler]
+ end
+
+ it "accepts an object and a callable" do
+ handler = mock("callable")
+ def handler.call(obj) end
+ ObjectSpace.define_finalizer("garbage", handler).should == [0, handler]
+ end
+
+ it "raises ArgumentError trying to define a finalizer on a non-reference" do
+ lambda {
+ ObjectSpace.define_finalizer(:blah) { 1 }
+ }.should raise_error(ArgumentError)
+ end
+
+ # see [ruby-core:24095]
+ with_feature :fork do
+ it "calls finalizer on process termination" do
+ rd, wr = IO.pipe
+ pid = Process.fork do
+ rd.close
+ handler = ObjectSpaceFixtures.scoped(wr)
+ obj = "Test"
+ ObjectSpace.define_finalizer(obj, handler)
+ exit 0
+ end
+
+ wr.close
+ begin
+ rd.read.should == "finalized"
+ ensure
+ rd.close
+ Process.wait pid
+ end
+ end
+
+ it "calls finalizer at exit even if it is self-referencing" do
+ rd, wr = IO.pipe
+ pid = Process.fork do
+ rd.close
+ obj = "Test"
+ handler = Proc.new { wr.write "finalized"; wr.close }
+ ObjectSpace.define_finalizer(obj, handler)
+ exit 0
+ end
+
+ wr.close
+ begin
+ rd.read.should == "finalized"
+ ensure
+ rd.close
+ Process.wait pid
+ end
+ end
+
+ # These specs are defined under the fork specs because there is no
+ # deterministic way to force finalizers to be run, except process exit, so
+ # we rely on that.
+ it "allows multiple finalizers with different 'callables' to be defined" do
+ rd1, wr1 = IO.pipe
+ rd2, wr2 = IO.pipe
+
+ pid = Kernel::fork do
+ rd1.close
+ rd2.close
+ obj = mock("ObjectSpace.define_finalizer multiple")
+
+ ObjectSpace.define_finalizer(obj, Proc.new { wr1.write "finalized1"; wr1.close })
+ ObjectSpace.define_finalizer(obj, Proc.new { wr2.write "finalized2"; wr2.close })
+
+ exit 0
+ end
+
+ wr1.close
+ wr2.close
+
+ rd1.read.should == "finalized1"
+ rd2.read.should == "finalized2"
+
+ rd1.close
+ rd2.close
+ Process.wait pid
+ end
+ end
+end