diff options
Diffstat (limited to 'spec/ruby/library/objectspace')
| -rw-r--r-- | spec/ruby/library/objectspace/dump_all_spec.rb | 112 | ||||
| -rw-r--r-- | spec/ruby/library/objectspace/dump_spec.rb | 70 | ||||
| -rw-r--r-- | spec/ruby/library/objectspace/fixtures/trace.rb | 6 | ||||
| -rw-r--r-- | spec/ruby/library/objectspace/memsize_of_all_spec.rb | 22 | ||||
| -rw-r--r-- | spec/ruby/library/objectspace/memsize_of_spec.rb | 6 | ||||
| -rw-r--r-- | spec/ruby/library/objectspace/reachable_objects_from_spec.rb | 14 | ||||
| -rw-r--r-- | spec/ruby/library/objectspace/trace_object_allocations_spec.rb | 163 | ||||
| -rw-r--r-- | spec/ruby/library/objectspace/trace_spec.rb | 13 |
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 |
