summaryrefslogtreecommitdiff
path: root/spec/ruby/library/objectspace
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/library/objectspace')
-rw-r--r--spec/ruby/library/objectspace/dump_all_spec.rb112
-rw-r--r--spec/ruby/library/objectspace/dump_spec.rb70
-rw-r--r--spec/ruby/library/objectspace/fixtures/trace.rb6
-rw-r--r--spec/ruby/library/objectspace/memsize_of_all_spec.rb22
-rw-r--r--spec/ruby/library/objectspace/memsize_of_spec.rb6
-rw-r--r--spec/ruby/library/objectspace/reachable_objects_from_spec.rb14
-rw-r--r--spec/ruby/library/objectspace/trace_object_allocations_spec.rb163
-rw-r--r--spec/ruby/library/objectspace/trace_spec.rb13
8 files changed, 395 insertions, 11 deletions
diff --git a/spec/ruby/library/objectspace/dump_all_spec.rb b/spec/ruby/library/objectspace/dump_all_spec.rb
new file mode 100644
index 0000000000..c92812ebd5
--- /dev/null
+++ b/spec/ruby/library/objectspace/dump_all_spec.rb
@@ -0,0 +1,112 @@
+require_relative '../../spec_helper'
+require 'objspace'
+
+describe "ObjectSpace.dump_all" do
+ it "dumps Ruby heap to string when passed output: :string" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ dump = ObjectSpace.dump_all(output: :string)
+ puts dump.class
+ puts dump.include?('"value":"abc"')
+ RUBY
+
+ stdout.should == "String\ntrue\n"
+ end
+
+ it "dumps Ruby heap to a temporary file when passed output: :file" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ file = ObjectSpace.dump_all(output: :file)
+
+ begin
+ file.flush
+ file.rewind
+ content = file.read
+
+ puts file.class
+ puts content.include?('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+ RUBY
+
+ stdout.should == "File\ntrue\n"
+ end
+
+ it "dumps Ruby heap to a temporary file when :output not specified" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ file = ObjectSpace.dump_all
+
+ begin
+ file.flush
+ file.rewind
+ content = file.read
+
+ puts file.class
+ puts content.include?('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+ RUBY
+
+ stdout.should == "File\ntrue\n"
+ end
+
+ it "dumps Ruby heap to a temporary file when passed output: :nil" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ file = ObjectSpace.dump_all(output: nil)
+
+ begin
+ file.flush
+ file.rewind
+ content = file.read
+
+ puts file.class
+ puts content.include?('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+ RUBY
+
+ stdout.should == "File\ntrue\n"
+ end
+
+ it "dumps Ruby heap to stdout when passed output: :stdout" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ ObjectSpace.dump_all(output: :stdout)
+ RUBY
+
+ stdout.should.include?('"value":"abc"')
+ end
+
+ it "dumps Ruby heap to provided IO when passed output: IO" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace -rtempfile")
+ string = "abc"
+ io = Tempfile.create("object_space_dump_all")
+
+ begin
+ result = ObjectSpace.dump_all(output: io)
+ io.rewind
+ content = io.read
+
+ puts result.equal?(io)
+ puts content.include?('"value":"abc"')
+ ensure
+ io.close
+ File.unlink io.path
+ end
+ RUBY
+
+ stdout.should == "true\ntrue\n"
+ end
+
+ it "raises ArgumentError when passed not supported :output value" do
+ -> { ObjectSpace.dump_all(output: Object.new) }.should.raise(ArgumentError, /wrong output option/)
+ end
+end
diff --git a/spec/ruby/library/objectspace/dump_spec.rb b/spec/ruby/library/objectspace/dump_spec.rb
new file mode 100644
index 0000000000..4b5e0da198
--- /dev/null
+++ b/spec/ruby/library/objectspace/dump_spec.rb
@@ -0,0 +1,70 @@
+require_relative '../../spec_helper'
+require 'objspace'
+
+describe "ObjectSpace.dump" do
+ it "dumps the content of object as JSON" do
+ require 'json'
+ string = ObjectSpace.dump("abc")
+ dump = JSON.parse(string)
+
+ dump['type'].should == "STRING"
+ dump['value'].should == "abc"
+ end
+
+ it "dumps to string when passed output: :string" do
+ string = ObjectSpace.dump("abc", output: :string)
+ string.should.is_a?(String)
+ string.should.include?('"value":"abc"')
+ end
+
+ it "dumps to string when :output not specified" do
+ string = ObjectSpace.dump("abc")
+ string.should.is_a?(String)
+ string.should.include?('"value":"abc"')
+ end
+
+ it "dumps to a temporary file when passed output: :file" do
+ file = ObjectSpace.dump("abc", output: :file)
+ file.should.is_a?(File)
+
+ file.rewind
+ content = file.read
+ content.should.include?('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+
+ it "dumps to a temporary file when passed output: :nil" do
+ file = ObjectSpace.dump("abc", output: nil)
+ file.should.is_a?(File)
+
+ file.rewind
+ file.read.should.include?('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+
+ it "dumps to stdout when passed output: :stdout" do
+ stdout = ruby_exe('ObjectSpace.dump("abc", output: :stdout)', options: "-robjspace").chomp
+ stdout.should.include?('"value":"abc"')
+ end
+
+ it "dumps to provided IO when passed output: IO" do
+ filename = tmp("io_read.txt")
+ io = File.open(filename, "w+")
+ result = ObjectSpace.dump("abc", output: io)
+ result.should.equal? io
+
+ io.rewind
+ io.read.should.include?('"value":"abc"')
+ ensure
+ io.close
+ rm_r filename
+ end
+
+ it "raises ArgumentError when passed not supported :output value" do
+ -> { ObjectSpace.dump("abc", output: Object.new) }.should.raise(ArgumentError, /wrong output option/)
+ end
+end
diff --git a/spec/ruby/library/objectspace/fixtures/trace.rb b/spec/ruby/library/objectspace/fixtures/trace.rb
new file mode 100644
index 0000000000..e53a7a0cac
--- /dev/null
+++ b/spec/ruby/library/objectspace/fixtures/trace.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: false
+require "objspace/trace"
+a = "foo"
+b = "b" + "a" + "r"
+c = 42
+p a, b, c
diff --git a/spec/ruby/library/objectspace/memsize_of_all_spec.rb b/spec/ruby/library/objectspace/memsize_of_all_spec.rb
new file mode 100644
index 0000000000..9fc6e8be9d
--- /dev/null
+++ b/spec/ruby/library/objectspace/memsize_of_all_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../spec_helper'
+require 'objspace'
+
+describe "ObjectSpace.memsize_of_all" do
+ it "returns a non-zero Integer for all objects" do
+ ObjectSpace.memsize_of_all.should.is_a?(Integer)
+ ObjectSpace.memsize_of_all.should > 0
+ end
+
+ it "returns a non-zero Integer for Class" do
+ ObjectSpace.memsize_of_all(Class).should.is_a?(Integer)
+ ObjectSpace.memsize_of_all(Class).should > 0
+ end
+
+ it "increases when a new object is allocated" do
+ c = Class.new
+ before = ObjectSpace.memsize_of_all(c)
+ o = c.new
+ after = ObjectSpace.memsize_of_all(c)
+ after.should > before
+ end
+end
diff --git a/spec/ruby/library/objectspace/memsize_of_spec.rb b/spec/ruby/library/objectspace/memsize_of_spec.rb
index 36d845824d..9c8aea4e84 100644
--- a/spec/ruby/library/objectspace/memsize_of_spec.rb
+++ b/spec/ruby/library/objectspace/memsize_of_spec.rb
@@ -13,12 +13,12 @@ describe "ObjectSpace.memsize_of" do
end
it "returns 0 for literal Symbols" do
- ObjectSpace.memsize_of(:abc).should == 0
+ ObjectSpace.memsize_of(:object_space_memsize_spec_static_sym).should == 0
end
- it "returns an Integer for an Object" do
+ it "returns a positive Integer for an Object" do
obj = Object.new
- ObjectSpace.memsize_of(obj).should be_kind_of(Integer)
+ ObjectSpace.memsize_of(obj).should.is_a?(Integer)
ObjectSpace.memsize_of(obj).should > 0
end
diff --git a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
index 7e70bc8569..4620bdec31 100644
--- a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
+++ b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
@@ -16,7 +16,7 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "enumerates objects directly reachable from a given object" do
- ObjectSpace.reachable_objects_from(['a', 'b', 'c']).should include(Array, 'a', 'b', 'c')
+ ObjectSpace.reachable_objects_from(['a', 'b', 'c']).to_set.should >= Set[Array, 'a', 'b', 'c']
ObjectSpace.reachable_objects_from(Object.new).should == [Object]
end
@@ -24,7 +24,7 @@ describe "ObjectSpace.reachable_objects_from" do
obj = Object.new
ary = [obj]
reachable = ObjectSpace.reachable_objects_from(ary)
- reachable.should include(obj)
+ reachable.should.include?(obj)
end
it "finds an object stored in a copy-on-write Array" do
@@ -33,29 +33,27 @@ describe "ObjectSpace.reachable_objects_from" do
ary = [removed, obj]
ary.shift
reachable = ObjectSpace.reachable_objects_from(ary)
- reachable.should include(obj)
- reachable.should_not include(removed)
+ reachable.should.include?(obj)
+ reachable.should_not.include?(removed)
end
it "finds an object stored in a Queue" do
- require 'thread'
o = Object.new
q = Queue.new
q << o
reachable = ObjectSpace.reachable_objects_from(q)
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
- reachable.should include(o)
+ reachable.should.include?(o)
end
it "finds an object stored in a SizedQueue" do
- require 'thread'
o = Object.new
q = SizedQueue.new(3)
q << o
reachable = ObjectSpace.reachable_objects_from(q)
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
- reachable.should include(o)
+ reachable.should.include?(o)
end
end
diff --git a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
new file mode 100644
index 0000000000..0bb6efbfa5
--- /dev/null
+++ b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
@@ -0,0 +1,163 @@
+require_relative '../../spec_helper'
+require 'objspace'
+
+describe "ObjectSpace.trace_object_allocations" do
+ def has_class_frame?
+ Class.new {
+ attr_reader :c
+
+ def initialize
+ @c = caller_locations.first.label =~ /new/
+ end
+ }.new.c
+ end
+
+ def obj_class_path
+ has_class_frame? ? "Class" : nil
+ end
+
+ it "runs a block" do
+ ScratchPad.clear
+ ObjectSpace.trace_object_allocations do
+ ScratchPad.record :a
+ end
+ ScratchPad.recorded.should == :a
+ end
+
+ it "records info for allocation_class_path" do
+ ObjectSpace.trace_object_allocations do
+ o = Object.new
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
+ a = [1, 2, 3]
+ ObjectSpace.allocation_class_path(a).should == nil
+ end
+ end
+
+ it "records info for allocation_generation" do
+ ObjectSpace.trace_object_allocations do
+ o = Object.new
+ ObjectSpace.allocation_generation(o).should.kind_of?(Integer)
+ a = [1, 2, 3]
+ ObjectSpace.allocation_generation(a).should.kind_of?(Integer)
+ end
+ end
+
+ it "records info for allocation_method_id" do
+ ObjectSpace.trace_object_allocations do
+ o = Object.new
+ ObjectSpace.allocation_method_id(o).should == (has_class_frame? ? :new : nil)
+ a = [1, 2, 3]
+ ObjectSpace.allocation_method_id(a).should == nil
+ end
+ end
+
+ it "records info for allocation_sourcefile" do
+ ObjectSpace.trace_object_allocations do
+ o = Object.new
+ ObjectSpace.allocation_sourcefile(o).should == __FILE__
+ a = [1, 2, 3]
+ ObjectSpace.allocation_sourcefile(a).should == __FILE__
+ end
+ end
+
+ it "records info for allocation_sourceline" do
+ ObjectSpace.trace_object_allocations do
+ o = Object.new
+ ObjectSpace.allocation_sourceline(o).should == __LINE__ - 1
+ a = [1, 2, 3]
+ ObjectSpace.allocation_sourceline(a).should == __LINE__ - 1
+ end
+ end
+
+ it "can be cleared using trace_object_allocations_clear" do
+ ObjectSpace.trace_object_allocations do
+ o = Object.new
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
+ ObjectSpace.trace_object_allocations_clear
+ ObjectSpace.allocation_class_path(o).should == nil
+ end
+ end
+
+ it "does not clears allocation data after returning" do
+ o = nil
+ ObjectSpace.trace_object_allocations do
+ o = Object.new
+ end
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
+ end
+
+ it "can be used without a block using trace_object_allocations_start and _stop" do
+ ObjectSpace.trace_object_allocations_start
+ begin
+ o = Object.new
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
+ a = [1, 2, 3]
+ ObjectSpace.allocation_class_path(a).should == nil
+ ensure
+ ObjectSpace.trace_object_allocations_stop
+ end
+ end
+
+ it "does not clears allocation data after trace_object_allocations_stop" do
+ ObjectSpace.trace_object_allocations_start
+ begin
+ o = Object.new
+ ensure
+ ObjectSpace.trace_object_allocations_stop
+ end
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
+ end
+
+ it "can be nested" do
+ ObjectSpace.trace_object_allocations do
+ ObjectSpace.trace_object_allocations do
+ o = Object.new
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
+ end
+ end
+ end
+
+ it "can be nested without a block using trace_object_allocations_start and _stop" do
+ ObjectSpace.trace_object_allocations_start
+ begin
+ ObjectSpace.trace_object_allocations_start
+ begin
+ o = Object.new
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
+ ensure
+ ObjectSpace.trace_object_allocations_stop
+ end
+ ensure
+ ObjectSpace.trace_object_allocations_stop
+ end
+ end
+
+ it "can be nested with more _stop than _start" do
+ ObjectSpace.trace_object_allocations_start
+ begin
+ o = Object.new
+ ObjectSpace.allocation_class_path(o).should == obj_class_path
+ ObjectSpace.trace_object_allocations_stop
+ ensure
+ ObjectSpace.trace_object_allocations_stop
+ end
+ end
+
+ it "returns nil for class_path, generation, method_id, sourcefile, and sourceline for immutable objects" do
+ ObjectSpace.trace_object_allocations_start
+ begin
+ one = nil
+ two = 42
+ three = :foo
+ [one, two, three].each do |i|
+ ObjectSpace.allocation_class_path(i).should == nil
+ ObjectSpace.allocation_generation(i).should == nil
+ ObjectSpace.allocation_method_id(i).should == nil
+ ObjectSpace.allocation_sourcefile(i).should == nil
+ ObjectSpace.allocation_sourceline(i).should == nil
+ end
+ ensure
+ ObjectSpace.trace_object_allocations_stop
+ end
+ end
+end
diff --git a/spec/ruby/library/objectspace/trace_spec.rb b/spec/ruby/library/objectspace/trace_spec.rb
new file mode 100644
index 0000000000..3957dc930d
--- /dev/null
+++ b/spec/ruby/library/objectspace/trace_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../spec_helper'
+
+describe 'require "objspace/trace"' do
+ it "shows object allocation sites" do
+ file = fixture(__FILE__ , "trace.rb")
+ ruby_exe(file, args: "2>&1").lines(chomp: true).should == [
+ "objspace/trace is enabled",
+ "\"foo\" @ #{file}:3",
+ "\"bar\" @ #{file}:4",
+ "42"
+ ]
+ end
+end