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 | 34 | ||||
| -rw-r--r-- | spec/ruby/library/objectspace/reachable_objects_from_spec.rb | 59 | ||||
| -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, 479 insertions, 0 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 new file mode 100644 index 0000000000..9c8aea4e84 --- /dev/null +++ b/spec/ruby/library/objectspace/memsize_of_spec.rb @@ -0,0 +1,34 @@ +require_relative '../../spec_helper' +require 'objspace' + +describe "ObjectSpace.memsize_of" do + it "returns 0 for true, false and nil" do + ObjectSpace.memsize_of(true).should == 0 + ObjectSpace.memsize_of(false).should == 0 + ObjectSpace.memsize_of(nil).should == 0 + end + + it "returns 0 for small Integers" do + ObjectSpace.memsize_of(42).should == 0 + end + + it "returns 0 for literal Symbols" do + ObjectSpace.memsize_of(:object_space_memsize_spec_static_sym).should == 0 + end + + it "returns a positive Integer for an Object" do + obj = Object.new + ObjectSpace.memsize_of(obj).should.is_a?(Integer) + ObjectSpace.memsize_of(obj).should > 0 + end + + it "is larger if the Object has more instance variables" do + obj = Object.new + before = ObjectSpace.memsize_of(obj) + 100.times do |i| + obj.instance_variable_set(:"@foo#{i}", nil) + end + after = ObjectSpace.memsize_of(obj) + after.should > before + end +end diff --git a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb new file mode 100644 index 0000000000..4620bdec31 --- /dev/null +++ b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb @@ -0,0 +1,59 @@ +require_relative '../../spec_helper' +require 'objspace' + +describe "ObjectSpace.reachable_objects_from" do + it "returns nil for true and false" do + ObjectSpace.reachable_objects_from(true).should == nil + ObjectSpace.reachable_objects_from(false).should == nil + end + + it "returns nil for nil" do + ObjectSpace.reachable_objects_from(nil).should == nil + end + + it "returns nil for small Integers" do + ObjectSpace.reachable_objects_from(42).should == nil + end + + it "enumerates objects directly reachable from a given object" do + ObjectSpace.reachable_objects_from(['a', 'b', 'c']).to_set.should >= Set[Array, 'a', 'b', 'c'] + ObjectSpace.reachable_objects_from(Object.new).should == [Object] + end + + it "finds an object stored in an Array" do + obj = Object.new + ary = [obj] + reachable = ObjectSpace.reachable_objects_from(ary) + reachable.should.include?(obj) + end + + it "finds an object stored in a copy-on-write Array" do + removed = Object.new + obj = Object.new + ary = [removed, obj] + ary.shift + reachable = ObjectSpace.reachable_objects_from(ary) + reachable.should.include?(obj) + reachable.should_not.include?(removed) + end + + it "finds an object stored in a Queue" do + 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) + end + + it "finds an object stored in a SizedQueue" do + 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) + 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 |
