diff options
Diffstat (limited to 'spec/ruby/core/tracepoint')
20 files changed, 1206 insertions, 0 deletions
diff --git a/spec/ruby/core/tracepoint/allow_reentry_spec.rb b/spec/ruby/core/tracepoint/allow_reentry_spec.rb new file mode 100644 index 0000000000..475cca29a9 --- /dev/null +++ b/spec/ruby/core/tracepoint/allow_reentry_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint.allow_reentry' do + it 'allows the reentrance in a given block' do + event_lines = [] + l1 = l2 = l3 = l4 = nil + TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + + event_lines << tp.lineno + next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno) + TracePoint.allow_reentry do + a = 1; l3 = __LINE__ + b = 2; l4 = __LINE__ + end + end.enable do + c = 3; l1 = __LINE__ + d = 4; l2 = __LINE__ + end + + event_lines.should == [l1, l3, l4, l2, l3, l4] + end + + it 'raises RuntimeError when not called inside a TracePoint' do + -> { + TracePoint.allow_reentry{} + }.should.raise(RuntimeError) + end +end diff --git a/spec/ruby/core/tracepoint/binding_spec.rb b/spec/ruby/core/tracepoint/binding_spec.rb new file mode 100644 index 0000000000..6de6e47d7d --- /dev/null +++ b/spec/ruby/core/tracepoint/binding_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#binding' do + def test + secret = 42 + end + + it 'return the generated binding object from event' do + bindings = [] + TracePoint.new(:return) { |tp| + next unless TracePointSpec.target_thread? + bindings << tp.binding + }.enable { + test + } + bindings.size.should == 1 + bindings[0].should.is_a?(Binding) + bindings[0].local_variables.should == [:secret] + end +end diff --git a/spec/ruby/core/tracepoint/callee_id_spec.rb b/spec/ruby/core/tracepoint/callee_id_spec.rb new file mode 100644 index 0000000000..cc08a45504 --- /dev/null +++ b/spec/ruby/core/tracepoint/callee_id_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "TracePoint#callee_id" do + it "returns the called name of the method being called" do + a = [] + obj = TracePointSpec::ClassWithMethodAlias.new + + TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? + a << tp.callee_id + end.enable do + obj.m_alias + end + + a.should == [:m_alias] + end +end diff --git a/spec/ruby/core/tracepoint/defined_class_spec.rb b/spec/ruby/core/tracepoint/defined_class_spec.rb new file mode 100644 index 0000000000..53c86a8210 --- /dev/null +++ b/spec/ruby/core/tracepoint/defined_class_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#defined_class' do + it 'returns class or module of the method being called' do + last_class_name = nil + TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? + last_class_name = tp.defined_class + end.enable do + TracePointSpec::B.new.foo + last_class_name.should.equal?(TracePointSpec::B) + + TracePointSpec::B.new.bar + last_class_name.should.equal?(TracePointSpec::A) + + c = TracePointSpec::C.new + last_class_name.should.equal?(TracePointSpec::C) + + c.foo + last_class_name.should.equal?(TracePointSpec::B) + + c.bar + last_class_name.should.equal?(TracePointSpec::A) + end + end +end diff --git a/spec/ruby/core/tracepoint/disable_spec.rb b/spec/ruby/core/tracepoint/disable_spec.rb new file mode 100644 index 0000000000..73a31b3b81 --- /dev/null +++ b/spec/ruby/core/tracepoint/disable_spec.rb @@ -0,0 +1,76 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#disable' do + it 'returns true if trace was enabled' do + called = false + trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + called = true + end + + trace.enable + begin + line_event = true + ensure + ret = trace.disable + ret.should == true + end + called.should == true + + # Check the TracePoint is disabled + called = false + line_event = true + called.should == false + end + + it 'returns false if trace was disabled' do + called = false + trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + called = true + end + + line_event = true + trace.disable.should == false + line_event = true + called.should == false + end + + it 'is disabled within a block & is enabled outside the block' do + enabled = nil + trace = TracePoint.new(:line) {} + trace.enable + begin + trace.disable { enabled = trace.enabled? } + enabled.should == false + trace.should.enabled? + ensure + trace.disable + end + end + + it 'returns the return value of the block' do + trace = TracePoint.new(:line) {} + trace.enable + begin + trace.disable { 42 }.should == 42 + trace.should.enabled? + ensure + trace.disable + end + end + + it 'can accept param within a block but it should not yield arguments' do + trace = TracePoint.new(:line) {} + trace.enable + begin + trace.disable do |*args| + args.should == [] + end + trace.should.enabled? + ensure + trace.disable + end + end +end diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb new file mode 100644 index 0000000000..bf61c35154 --- /dev/null +++ b/spec/ruby/core/tracepoint/enable_spec.rb @@ -0,0 +1,543 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#enable' do + describe 'without a block' do + it 'returns false if trace was disabled' do + called = false + trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + called = true + end + + line_event = true + called.should == false + + ret = trace.enable + begin + ret.should == false + line_event = true + called.should == true + ensure + trace.disable + end + end + + it 'returns true if trace was already enabled' do + called = false + trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + called = true + end + + line_event = true + called.should == false + + ret = trace.enable + begin + ret.should == false + + trace.enable.should == true + + line_event = true + called.should == true + ensure + trace.disable + trace.should_not.enabled? + end + end + end + + describe 'with a block' do + it 'enables the trace object within a block' do + event_name = nil + TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + end.enable { event_name.should.equal?(:line) } + end + + it 'enables the trace object only for the current thread' do + threads = [] + trace = TracePoint.new(:line) do |tp| + # Runs on purpose on any Thread + threads << Thread.current + end + + thread = nil + trace.enable do + line_event = true + thread = Thread.new do + event_in_other_thread = true + end + thread.join + end + + threads = threads.uniq + threads.should.include?(Thread.current) + threads.should_not.include?(thread) + end + + it 'can accept arguments within a block but it should not yield arguments' do + event_name = nil + trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + end + trace.enable do |*args| + event_name.should.equal?(:line) + args.should == [] + end + trace.should_not.enabled? + end + + it 'enables trace object on calling with a block if it was already enabled' do + enabled = nil + trace = TracePoint.new(:line) {} + trace.enable + begin + trace.enable { enabled = trace.enabled? } + enabled.should == true + ensure + trace.disable + end + end + + it 'returns the return value of the block' do + trace = TracePoint.new(:line) {} + trace.enable { 42 }.should == 42 + end + + it 'disables the trace object outside the block' do + called = false + trace = TracePoint.new(:line) do + next unless TracePointSpec.target_thread? + called = true + end + trace.enable { + line_event = true + } + called.should == true + trace.should_not.enabled? + end + end + + describe "when nested" do + before do + @path_prefix = ' ' + end + + it "enables both TracePoints but only calls the respective callbacks" do + called = false + first = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + called = true + end + + all = [] + inspects = [] + second = TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + all << tp + inspects << tp.inspect + } + + line = nil + first.enable do + second.enable do + line = __LINE__ + end + end + + all.uniq.should == [second] + inspects.uniq.should == ["#<TracePoint:line#{@path_prefix}#{__FILE__}:#{line}>"] + called.should == true + end + end + + describe 'target: option' do + before :each do + ScratchPad.record [] + end + + it 'enables trace point for specific location' do + trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.method_id + end + + obj = Object.new + def obj.foo; end + def obj.bar; end + + trace.enable(target: obj.method(:foo)) do + obj.foo + obj.bar + end + + ScratchPad.recorded.should == [:foo] + end + + it 'traces all the events triggered in specified location' do + trace = TracePoint.new(:line, :call, :return, :b_call, :b_return) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.event + end + + obj = Object.new + def obj.foo + bar + -> {}.call + end + def obj.bar; end + + trace.enable(target: obj.method(:foo)) do + obj.foo + end + + ScratchPad.recorded.uniq.sort.should == [:call, :return, :b_call, :b_return, :line].sort + end + + it 'does not trace events in nested locations' do + trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.method_id + end + + obj = Object.new + def obj.foo + bar + end + def obj.bar + baz + end + def obj.baz + end + + trace.enable(target: obj.method(:foo)) do + obj.foo + end + + ScratchPad.recorded.should == [:foo] + end + + it "traces some events in nested blocks" do + klass = Class.new do + def foo + 1.times do + 1.times do + bar do + end + end + end + end + + def bar(&blk) + blk.call + end + end + + trace = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.lineno + end + + obj = klass.new + _, lineno = obj.method(:foo).source_location + + trace.enable(target: obj.method(:foo)) do + obj.foo + end + + ScratchPad.recorded.should == (lineno+1..lineno+3).to_a + end + + describe 'option value' do + it 'accepts Method' do + trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.method_id + end + + obj = Object.new + def obj.foo; end + + trace.enable(target: obj.method(:foo)) do + obj.foo + end + + ScratchPad.recorded.should == [:foo] + end + + it 'accepts UnboundMethod' do + trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.method_id + end + + klass = Class.new do + def foo; end + end + + unbound_method = klass.instance_method(:foo) + trace.enable(target: unbound_method) do + klass.new.foo + end + + ScratchPad.recorded.should == [:foo] + end + + it 'accepts Proc' do + trace = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.lineno + end + + block = proc {} + _, lineno = block.source_location + + trace.enable(target: block) do + block.call + end + + ScratchPad.recorded.should == [lineno] + lineno.should.is_a?(Integer) + end + end + + it "raises ArgumentError if target object cannot trigger specified event" do + trace = TracePoint.new(:call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.method_id + end + + block = proc {} + + -> { + trace.enable(target: block) do + block.call # triggers :b_call and :b_return events + end + }.should.raise(ArgumentError, /can not enable any hooks/) + end + + it "raises ArgumentError if passed not Method/UnboundMethod/Proc" do + trace = TracePoint.new(:call) {} + + -> { + trace.enable(target: Object.new) do + end + }.should.raise(ArgumentError, /specified target is not supported/) + end + + context "nested enabling and disabling" do + it "raises ArgumentError if trace point already enabled with target is re-enabled with target" do + trace = TracePoint.new(:b_call) {} + + -> { + trace.enable(target: -> {}) do + trace.enable(target: -> {}) do + end + end + }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/) + end + + it "raises ArgumentError if trace point already enabled without target is re-enabled with target" do + trace = TracePoint.new(:b_call) {} + + -> { + trace.enable do + trace.enable(target: -> {}) do + end + end + }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/) + end + + it "raises ArgumentError if trace point already enabled with target is re-enabled without target" do + trace = TracePoint.new(:b_call) {} + + -> { + trace.enable(target: -> {}) do + trace.enable do + end + end + }.should.raise(ArgumentError, /can't nest-enable a targett?ing TracePoint/) + end + + it "raises ArgumentError if trace point already enabled with target is disabled with block" do + trace = TracePoint.new(:b_call) {} + + -> { + trace.enable(target: -> {}) do + trace.disable do + end + end + }.should.raise(ArgumentError, /can't disable a targett?ing TracePoint in a block/) + end + + it "traces events when trace point with target is enabled in another trace point enabled without target" do + trace_outer = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << :outer + end + + trace_inner = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << :inner + end + + target = -> {} + + trace_outer.enable do + trace_inner.enable(target: target) do + target.call + end + end + + ScratchPad.recorded.should == [:outer, :outer, :outer, :inner] + end + + it "traces events when trace point with target is enabled in another trace point enabled with target" do + trace_outer = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << :outer + end + + trace_inner = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << :inner + end + + target = -> {} + + trace_outer.enable(target: target) do + trace_inner.enable(target: target) do + target.call + end + end + + ScratchPad.recorded.should == [:inner, :outer] + end + + it "traces events when trace point without target is enabled in another trace point enabled with target" do + trace_outer = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << :outer + end + + trace_inner = TracePoint.new(:b_call) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << :inner + end + + target = -> {} + + trace_outer.enable(target: target) do + trace_inner.enable do + target.call + end + end + + ScratchPad.recorded.should == [:inner, :inner, :outer] + end + end + end + + describe 'target_line: option' do + before :each do + ScratchPad.record [] + end + + it "traces :line events only on specified line of code" do + trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.lineno + end + + target = -> { + x = 1 + y = 2 # <= this line is target + z = x + y + } + _, lineno = target.source_location + target_line = lineno + 2 + + trace.enable(target_line: target_line, target: target) do + target.call + end + + ScratchPad.recorded.should == [target_line] + end + + it "raises ArgumentError if :target option isn't specified" do + trace = TracePoint.new(:line) {} + + -> { + trace.enable(target_line: 67) do + end + }.should.raise(ArgumentError, /only target_line is specified/) + end + + it "raises ArgumentError if :line event isn't registered" do + trace = TracePoint.new(:call) {} + + target = -> { + x = 1 + y = 2 # <= this line is target + z = x + y + } + _, lineno = target.source_location + target_line = lineno + 2 + + -> { + trace.enable(target_line: target_line, target: target) do + end + }.should.raise(ArgumentError, /target_line is specified, but line event is not specified/) + end + + it "raises ArgumentError if :target_line value is out of target code lines range" do + trace = TracePoint.new(:line) {} + + -> { + trace.enable(target_line: 1, target: -> { }) do + end + }.should.raise(ArgumentError, /can not enable any hooks/) + end + + it "raises TypeError if :target_line value couldn't be coerced to Integer" do + trace = TracePoint.new(:line) {} + + -> { + trace.enable(target_line: Object.new, target: -> { }) do + end + }.should.raise(TypeError, /no implicit conversion of \w+? into Integer/) + end + + it "raises ArgumentError if :target_line value is negative" do + trace = TracePoint.new(:line) {} + + -> { + trace.enable(target_line: -2, target: -> { }) do + end + }.should.raise(ArgumentError, /can not enable any hooks/) + end + + it "accepts value that could be coerced to Integer" do + trace = TracePoint.new(:line) do |tp| + next unless TracePointSpec.target_thread? + ScratchPad << tp.lineno + end + + target = -> { + x = 1 # <= this line is target + } + _, lineno = target.source_location + target_line = lineno + 1 + + trace.enable(target_line: target_line.to_r, target: target) do + target.call + end + + ScratchPad.recorded.should == [target_line] + end + end +end diff --git a/spec/ruby/core/tracepoint/enabled_spec.rb b/spec/ruby/core/tracepoint/enabled_spec.rb new file mode 100644 index 0000000000..0e9566a02c --- /dev/null +++ b/spec/ruby/core/tracepoint/enabled_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#enabled?' do + it 'returns true when current status of the trace is enable' do + trace = TracePoint.new(:line) {} + trace.enable do + trace.should.enabled? + end + end + + it 'returns false when current status of the trace is disabled' do + TracePoint.new(:line) {}.should_not.enabled? + end +end diff --git a/spec/ruby/core/tracepoint/eval_script_spec.rb b/spec/ruby/core/tracepoint/eval_script_spec.rb new file mode 100644 index 0000000000..7ec53e7094 --- /dev/null +++ b/spec/ruby/core/tracepoint/eval_script_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "TracePoint#eval_script" do + it "is the evald source code" do + ScratchPad.record [] + + script = <<-CODE + def foo + p :hello + end + CODE + + TracePoint.new(:script_compiled) do |e| + next unless TracePointSpec.target_thread? + ScratchPad << e.eval_script + end.enable do + eval script + end + + ScratchPad.recorded.should == [script] + end +end diff --git a/spec/ruby/core/tracepoint/event_spec.rb b/spec/ruby/core/tracepoint/event_spec.rb new file mode 100644 index 0000000000..58017dc98d --- /dev/null +++ b/spec/ruby/core/tracepoint/event_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#event' do + it 'returns the type of event' do + event_name = nil + TracePoint.new(:end, :call) do |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + end.enable do + TracePointSpec.test + event_name.should.equal?(:call) + + TracePointSpec::B.new.foo + event_name.should.equal?(:call) + + class TracePointSpec::B; end + event_name.should.equal?(:end) + end + + end +end diff --git a/spec/ruby/core/tracepoint/fixtures/classes.rb b/spec/ruby/core/tracepoint/fixtures/classes.rb new file mode 100644 index 0000000000..3ab1b00b16 --- /dev/null +++ b/spec/ruby/core/tracepoint/fixtures/classes.rb @@ -0,0 +1,40 @@ +module TracePointSpec + @thread = Thread.current + + def self.target_thread? + Thread.current == @thread + end + + class ClassWithMethodAlias + def m + end + alias_method :m_alias, :m + end + + module A + def bar; end + end + + class B + include A + + def foo; end; + end + + class C < B + def initialize + end + + def foo + super + end + + def bar + super + end + end + + def self.test + 'test' + end +end diff --git a/spec/ruby/core/tracepoint/inspect_spec.rb b/spec/ruby/core/tracepoint/inspect_spec.rb new file mode 100644 index 0000000000..6cc2ebe243 --- /dev/null +++ b/spec/ruby/core/tracepoint/inspect_spec.rb @@ -0,0 +1,141 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#inspect' do + before do + @path_prefix = ' ' + end + + it 'returns a string containing a human-readable TracePoint status' do + TracePoint.new(:line) {}.inspect.should == '#<TracePoint:disabled>' + end + + it "shows only whether it's enabled when outside the TracePoint handler" do + trace = TracePoint.new(:line) {} + trace.enable + + trace.inspect.should == '#<TracePoint:enabled>' + + trace.disable + end + + it 'returns a String showing the event, path and line' do + inspect = nil + line = nil + TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + next unless tp.path == __FILE__ + + inspect ||= tp.inspect + }.enable do + line = __LINE__ + end + + inspect.should == "#<TracePoint:line#{@path_prefix}#{__FILE__}:#{line}>" + end + + it 'returns a String showing the event, method, path and line for a :call event' do + inspect = nil + line = nil + TracePoint.new(:call) { |tp| + next unless TracePointSpec.target_thread? + next unless tp.path == __FILE__ + + inspect ||= tp.inspect + }.enable do + line = __LINE__ + 1 + def trace_point_spec_test_call; end + trace_point_spec_test_call + end + + inspect.should =~ /\A#<TracePoint:call [`']trace_point_spec_test_call'#{@path_prefix}#{__FILE__}:#{line}>\z/ + end + + it 'returns a String showing the event, method, path and line for a :return event' do + inspect = nil + line = nil + TracePoint.new(:return) { |tp| + next unless TracePointSpec.target_thread? + next unless tp.path == __FILE__ + + inspect ||= tp.inspect + }.enable do + line = __LINE__ + 4 + def trace_point_spec_test_return + a = 1 + return a + end + trace_point_spec_test_return + end + ruby_version_is("3.4") { line -= 1 } + + inspect.should =~ /\A#<TracePoint:return [`']trace_point_spec_test_return'#{@path_prefix}#{__FILE__}:#{line}>\z/ + end + + it 'returns a String showing the event, method, path and line for a :c_call event' do + inspect = nil + tracepoint = TracePoint.new(:c_call) { |tp| + next unless TracePointSpec.target_thread? + next unless tp.path == __FILE__ + + inspect ||= tp.inspect + } + line = __LINE__ + 2 + tracepoint.enable do + [0, 1].max + end + + inspect.should =~ /\A#<TracePoint:c_call [`']max'#{@path_prefix}#{__FILE__}:#{line}>\z/ + end + + it 'returns a String showing the event, path and line for a :class event' do + inspect = nil + line = nil + TracePoint.new(:class) { |tp| + next unless TracePointSpec.target_thread? + next unless tp.path == __FILE__ + + inspect ||= tp.inspect + }.enable do + line = __LINE__ + 1 + class TracePointSpec::C + end + end + + inspect.should == "#<TracePoint:class#{@path_prefix}#{__FILE__}:#{line}>" + end + + it 'returns a String showing the event and thread for :thread_begin event' do + inspect = nil + thread = nil + thread_inspection = nil + TracePoint.new(:thread_begin) { |tp| + next unless Thread.current == thread + + inspect ||= tp.inspect + }.enable(target_thread: nil) do + thread = Thread.new {} + thread_inspection = thread.inspect + thread.join + end + + inspect.should == "#<TracePoint:thread_begin #{thread_inspection}>" + end + + it 'returns a String showing the event and thread for :thread_end event' do + inspect = nil + thread = nil + thread_inspection = nil + TracePoint.new(:thread_end) { |tp| + next unless Thread.current == thread + + inspect ||= tp.inspect + }.enable(target_thread: nil) do + thread = Thread.new {} + thread_inspection = thread.inspect + thread.join + end + + inspect.should == "#<TracePoint:thread_end #{thread_inspection}>" + end +end diff --git a/spec/ruby/core/tracepoint/lineno_spec.rb b/spec/ruby/core/tracepoint/lineno_spec.rb new file mode 100644 index 0000000000..7c46d5222b --- /dev/null +++ b/spec/ruby/core/tracepoint/lineno_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#lineno' do + it 'returns the line number of the event' do + lineno = nil + TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + lineno = tp.lineno + }.enable do + line_event = true + end + lineno.should == __LINE__ - 2 + end + + it 'raises RuntimeError if accessed from outside' do + tp = TracePoint.new(:line) {} + -> { tp.lineno }.should.raise(RuntimeError, 'access from outside') + end +end diff --git a/spec/ruby/core/tracepoint/method_id_spec.rb b/spec/ruby/core/tracepoint/method_id_spec.rb new file mode 100644 index 0000000000..67740f2d7d --- /dev/null +++ b/spec/ruby/core/tracepoint/method_id_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#method_id' do + it 'returns the name at the definition of the method being called' do + method_name = nil + TracePoint.new(:call) { |tp| + next unless TracePointSpec.target_thread? + method_name = tp.method_id + }.enable do + TracePointSpec.test + method_name.should.equal?(:test) + end + end +end diff --git a/spec/ruby/core/tracepoint/new_spec.rb b/spec/ruby/core/tracepoint/new_spec.rb new file mode 100644 index 0000000000..763b35292b --- /dev/null +++ b/spec/ruby/core/tracepoint/new_spec.rb @@ -0,0 +1,72 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint.new' do + it 'returns a new TracePoint object, not enabled by default' do + TracePoint.new(:line) {}.enabled?.should == false + end + + it 'includes :line event when event is not specified' do + event_name = nil + TracePoint.new { |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + }.enable do + event_name.should.equal?(:line) + + event_name = nil + TracePointSpec.test + event_name.should.equal?(:line) + + event_name = nil + TracePointSpec::B.new.foo + event_name.should.equal?(:line) + end + end + + it 'converts given event name as string into symbol using to_sym' do + event_name = nil + (o = mock('line')).should_receive(:to_sym).and_return(:line) + + TracePoint.new(o) { |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + }.enable do + line_event = true + event_name.should == :line + end + end + + it 'includes multiple events when multiple event names are passed as params' do + event_name = nil + TracePoint.new(:end, :call) do |tp| + next unless TracePointSpec.target_thread? + event_name = tp.event + end.enable do + TracePointSpec.test + event_name.should.equal?(:call) + + TracePointSpec::B.new.foo + event_name.should.equal?(:call) + + class TracePointSpec::B; end + event_name.should.equal?(:end) + end + end + + it 'raises a TypeError when the given object is not a string/symbol' do + o = mock('123') + -> { TracePoint.new(o) {} }.should.raise(TypeError) + + o.should_receive(:to_sym).and_return(123) + -> { TracePoint.new(o) {} }.should.raise(TypeError) + end + + it 'expects to be called with a block' do + -> { TracePoint.new(:line) }.should.raise(ArgumentError, "must be called with a block") + end + + it "raises a Argument error when the given argument doesn't match an event name" do + -> { TracePoint.new(:test) }.should.raise(ArgumentError, "unknown event: test") + end +end diff --git a/spec/ruby/core/tracepoint/parameters_spec.rb b/spec/ruby/core/tracepoint/parameters_spec.rb new file mode 100644 index 0000000000..82aee3caa4 --- /dev/null +++ b/spec/ruby/core/tracepoint/parameters_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#parameters' do + it 'returns the parameters of block' do + f = proc {|x, y, z| } + parameters = nil + TracePoint.new(:b_call) { |tp| + next unless TracePointSpec.target_thread? + parameters = tp.parameters + }.enable do + f.call + parameters.should == [[:opt, :x], [:opt, :y], [:opt, :z]] + end + end + + it 'returns the parameters of lambda block' do + f = -> x, y, z { } + parameters = nil + TracePoint.new(:b_call) { |tp| + next unless TracePointSpec.target_thread? + parameters = tp.parameters + }.enable do + f.call(1, 2, 3) + parameters.should == [[:req, :x], [:req, :y], [:req, :z]] + end + end +end diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb new file mode 100644 index 0000000000..aa6868ead2 --- /dev/null +++ b/spec/ruby/core/tracepoint/path_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#path' do + it 'returns the path of the file being run' do + path = nil + TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + path = tp.path + }.enable do + line_event = true + end + path.should == "#{__FILE__}" + end + + it 'equals "(eval at __FILE__:__LINE__)" inside an eval for :end event' do + path = nil + TracePoint.new(:end) { |tp| + next unless TracePointSpec.target_thread? + path = tp.path + }.enable do + eval("module TracePointSpec; end") + end + path.should == "(eval at #{__FILE__}:#{__LINE__ - 2})" + end +end diff --git a/spec/ruby/core/tracepoint/raised_exception_spec.rb b/spec/ruby/core/tracepoint/raised_exception_spec.rb new file mode 100644 index 0000000000..b1199902f2 --- /dev/null +++ b/spec/ruby/core/tracepoint/raised_exception_spec.rb @@ -0,0 +1,36 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#raised_exception' do + it 'returns value from exception raised on the :raise event' do + raised_exception, error_result = nil + trace = TracePoint.new(:raise) { |tp| + next unless TracePointSpec.target_thread? + raised_exception = tp.raised_exception + } + trace.enable do + begin + raise StandardError + rescue => e + error_result = e + end + raised_exception.should.equal?(error_result) + end + end + + it 'returns value from exception rescued on the :rescue event' do + raised_exception, error_result = nil + trace = TracePoint.new(:rescue) { |tp| + next unless TracePointSpec.target_thread? + raised_exception = tp.raised_exception + } + trace.enable do + begin + raise StandardError + rescue => e + error_result = e + end + raised_exception.should.equal?(error_result) + end + end +end diff --git a/spec/ruby/core/tracepoint/return_value_spec.rb b/spec/ruby/core/tracepoint/return_value_spec.rb new file mode 100644 index 0000000000..e84c7dd762 --- /dev/null +++ b/spec/ruby/core/tracepoint/return_value_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#return_value' do + def test; 'test' end + + it 'returns value from :return event' do + trace_value = nil + TracePoint.new(:return) { |tp| + next unless TracePointSpec.target_thread? + trace_value = tp.return_value + }.enable do + test + trace_value.should == 'test' + end + end +end diff --git a/spec/ruby/core/tracepoint/self_spec.rb b/spec/ruby/core/tracepoint/self_spec.rb new file mode 100644 index 0000000000..bf9a2b6a45 --- /dev/null +++ b/spec/ruby/core/tracepoint/self_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint#self' do + it 'return the trace object from event' do + trace = nil + TracePoint.new(:line) { |tp| + next unless TracePointSpec.target_thread? + trace = tp.self + }.enable do + trace.equal?(self).should == true + end + end + + it 'return the class object from a class event' do + trace = nil + TracePoint.new(:class) { |tp| + next unless TracePointSpec.target_thread? + trace = tp.self + }.enable do + class TracePointSpec::C + end + end + trace.should.equal? TracePointSpec::C + end +end diff --git a/spec/ruby/core/tracepoint/trace_spec.rb b/spec/ruby/core/tracepoint/trace_spec.rb new file mode 100644 index 0000000000..167f594bb9 --- /dev/null +++ b/spec/ruby/core/tracepoint/trace_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe 'TracePoint.trace' do + it 'activates the trace automatically' do + trace = TracePoint.trace(:line) {} + trace.should.enabled? + trace.disable + end +end |
