Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,3 @@ gem "rake", "~> 13.0"
gem "irb"

gem "test-unit", "~> 3.0"

gem "ruby-lsp"
10 changes: 0 additions & 10 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,10 @@ GEM
io-console (0.6.0)
irb (1.6.2)
reline (>= 0.3.0)
language_server-protocol (3.17.0.3)
power_assert (2.0.2)
prettier_print (1.2.0)
rake (13.0.6)
reline (0.3.2)
io-console (~> 0.5)
ruby-lsp (0.3.8)
language_server-protocol (~> 3.17.0)
sorbet-runtime
syntax_tree (>= 5.0.0, < 6)
sorbet-runtime (0.5.10648)
syntax_tree (5.3.0)
prettier_print (>= 1.2.0)
test-unit (3.5.5)
power_assert

Expand All @@ -33,7 +24,6 @@ PLATFORMS
DEPENDENCIES
irb
rake (~> 13.0)
ruby-lsp
test-unit (~> 3.0)
tracer!

Expand Down
25 changes: 17 additions & 8 deletions lib/tracer/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,21 @@ def pretty_path(path)
end
end

def initialize(output: STDOUT, pattern: nil, colorize: nil, depth_offset: 0)
attr_reader :header

def initialize(
output: STDOUT,
pattern: nil,
colorize: nil,
depth_offset: 0,
header: nil
)
@name = self.class.name
@type = @name.sub(/Tracer\z/, "")
@output = output
@depth_offset = depth_offset
@colorize = colorize || colorizable?
@header = header

if pattern
@pattern = Regexp.compile(pattern)
Expand All @@ -90,10 +99,6 @@ def key
[@type, @pattern, @into].freeze
end

def header
""
end

def to_s
s = "#{@name} #{description}"
s += " with pattern #{@pattern.inspect}" if @pattern
Expand Down Expand Up @@ -141,10 +146,14 @@ def skip_internal?(tp)

def out(tp, msg = nil, depth: caller.size - 1, location: nil)
location ||= "#{tp.path}:#{tp.lineno}"
buff =
"#{header} \#depth:#{"%-2d" % depth}#{msg} at #{colorize("#{location}", [:GREEN])}"
if header
str = +"#{header} "
else
str = +""
end
str << "\#depth:#{"%-2d" % depth}#{msg} at #{colorize("#{location}", [:GREEN])}"

puts buff
puts str
end

def puts(msg)
Expand Down
46 changes: 0 additions & 46 deletions test/ruby_tracer/call_tracer_test.rb

This file was deleted.

77 changes: 77 additions & 0 deletions test/tracer/call_tracer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
require_relative "../test_helper"

module Tracer
class CallTracerTest < TestCase
include ActivationTests

private

def build_tracer
CallTracer.new(output: @output)
end
end

class CallTracerIntegrationTest < IntegrationTestCase
def test_object_tracer_traces_method_calls
file = write_file("foo.rb", <<~RUBY)
obj = Object.new

def obj.foo
100
end

def bar(obj)
obj.foo
end

CallTracer.new.start

bar(obj)
RUBY

out, err = execute_file(file)

assert_empty(err)
assert_traces(
[
%r{^#depth:0 > Object#bar at .*/foo\.rb:13},
%r{^#depth:1 > #<Object:.*>\.foo at .*/foo\.rb:8},
%r{^#depth:1 < #<Object:.*>\.foo #=> 100 at .*/foo\.rb:8},
%r{^#depth:0 < Object#bar #=> 100 at .*/foo\.rb:13}
],
out
)
end

def test_object_tracer_with_header
file = write_file("foo.rb", <<~RUBY)
obj = Object.new

def obj.foo
100
end

def bar(obj)
obj.foo
end

CallTracer.new(header: "tracer-1").start

bar(obj)
RUBY

out, err = execute_file(file)

assert_empty(err)
assert_traces(
[
%r{^tracer-1 #depth:0 > Object#bar at .*/foo\.rb:13},
%r{^tracer-1 #depth:1 > #<Object:.*>\.foo at .*/foo\.rb:8},
%r{^tracer-1 #depth:1 < #<Object:.*>\.foo #=> 100 at .*/foo\.rb:8},
%r{^tracer-1 #depth:0 < Object#bar #=> 100 at .*/foo\.rb:13}
],
out
)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,20 @@ def test_exception_tracer_traces_exceptions
out, err = execute_file(file)

assert_empty(err)
assert_traces([/#depth:0 #<RuntimeError: boom> at .*foo.rb:3/], out)
assert_traces([/^#depth:0 #<RuntimeError: boom> at .*foo.rb:3/], out)
end

def test_exception_tracer_with_header
file = write_file("foo.rb", <<~RUBY)
ExceptionTracer.new(header: "tracer-1").start

raise "boom" rescue nil
RUBY

out, err = execute_file(file)

assert_empty(err)
assert_traces([/^tracer-1 #depth:0 #<RuntimeError: boom> at .*foo.rb:3/], out)
end
end
end
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,21 @@ def test_line_tracer_traces_line_executions
out, err = execute_file(file)

assert_empty(err)
assert_traces([/#depth:1 at .*foo.rb:3/, /#depth:1 at .*foo.rb:4/], out)
assert_traces([/^#depth:1 at .*foo.rb:3/, /#depth:1 at .*foo.rb:4/], out)
end

def test_line_tracer_with_header
file = write_file("foo.rb", <<~RUBY)
LineTracer.new(header: "tracer-1").start

a = 1
b = 2
RUBY

out, err = execute_file(file)

assert_empty(err)
assert_traces([/^tracer-1 #depth:1 at .*foo.rb:3/, /#depth:1 at .*foo.rb:4/], out)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,37 @@ def bar(obj)
assert_empty(err)
assert_traces(
[
%r{#depth:0 #<Object:.*> is used as a parameter obj of Object#bar at .*/foo\.rb:13},
%r{#depth:1 #<Object:.*> receives \.foo at .*/foo\.rb:8}
%r{^#depth:0 #<Object:.*> is used as a parameter obj of Object#bar at .*/foo\.rb:13},
%r{^#depth:1 #<Object:.*> receives \.foo at .*/foo\.rb:8}
],
out
)
end

def test_object_tracer_with_header
file = write_file("foo.rb", <<~RUBY)
obj = Object.new

def obj.foo
100
end

def bar(obj)
obj.foo
end

ObjectTracer.new(obj, header: "tracer-1").start

bar(obj)
RUBY

out, err = execute_file(file)

assert_empty(err)
assert_traces(
[
%r{tracer-1 #depth:0 #<Object:.*> is used as a parameter obj of Object#bar at .*/foo\.rb:13},
%r{tracer-1 #depth:1 #<Object:.*> receives \.foo at .*/foo\.rb:8}
],
out
)
Expand All @@ -78,8 +107,8 @@ def bar(**kwargs)
assert_empty(err)
assert_traces(
[
%r{#depth:0 #<Object:.*> is used as a parameter in args of Object#foo at .*/foo\.rb:11},
%r{#depth:0 #<Object:.*> is used as a parameter in kwargs of Object#bar at .*/foo\.rb:12}
%r{^#depth:0 #<Object:.*> is used as a parameter in args of Object#foo at .*/foo\.rb:11},
%r{^#depth:0 #<Object:.*> is used as a parameter in kwargs of Object#bar at .*/foo\.rb:12}
],
out
)
Expand Down Expand Up @@ -108,9 +137,9 @@ def bar(**kwargs)
assert_empty(err)
assert_traces(
[
%r{#depth:0 #<Object:.*> is used as a parameter in args of Object#foo at .*/foo\.rb:12},
%r{#depth:1 #<Object:.*> is used as a parameter obj of block{} at .*/foo\.rb:4},
%r{#depth:2 #<Object:.*> is used as a parameter in kwargs of Object#bar at .*/foo\.rb:13}
%r{^#depth:0 #<Object:.*> is used as a parameter in args of Object#foo at .*/foo\.rb:12},
%r{^#depth:1 #<Object:.*> is used as a parameter obj of block{} at .*/foo\.rb:4},
%r{^#depth:2 #<Object:.*> is used as a parameter in kwargs of Object#bar at .*/foo\.rb:13}
],
out
)
Expand Down Expand Up @@ -138,8 +167,8 @@ def bar(obj)
assert_empty(err)
assert_traces(
[
%r{#depth:0 #<Object:.*> is used as a parameter obj of Object#bar at .*/foo\.rb:13},
%r{#depth:1 #<Object:.*> receives \.foo at .*/foo\.rb:8}
%r{^#depth:0 #<Object:.*> is used as a parameter obj of Object#bar at .*/foo\.rb:13},
%r{^#depth:1 #<Object:.*> receives \.foo at .*/foo\.rb:8}
],
out
)
Expand Down Expand Up @@ -174,8 +203,8 @@ def test_object_tracer_works_with_nil_defined_class
assert_empty(err)
assert_traces(
[
/#depth:-1 #<Object:.*> receives #instance_eval \(BasicObject#instance_eval\) at .*foo\.rb:4/,
/#depth:1 #<Object:.*> receives <eval or exec with &block> at .*foo.rb:4:in `instance_eval'/
/^#depth:-1 #<Object:.*> receives #instance_eval \(BasicObject#instance_eval\) at .*foo\.rb:4/,
/^#depth:1 #<Object:.*> receives <eval or exec with &block> at .*foo.rb:4:in `instance_eval'/
],
out
)
Expand Down Expand Up @@ -208,9 +237,9 @@ def bar(obj)
assert_empty(err)
assert_traces(
[
%r{#depth:0 #<Foo.* does not have #inspect> is used as a parameter obj of Object#bar at .*/foo\.rb:17},
%r{#depth:1 #<Foo.* does not have #inspect> receives \.foo at .*/foo\.rb:12},
%r{#depth:0 #<Foo.* does not have #inspect> receives #baz \(Foo#baz\) at .*/foo\.rb:18}
%r{^#depth:0 #<Foo.* does not have #inspect> is used as a parameter obj of Object#bar at .*/foo\.rb:17},
%r{^#depth:1 #<Foo.* does not have #inspect> receives \.foo at .*/foo\.rb:12},
%r{^#depth:0 #<Foo.* does not have #inspect> receives #baz \(Foo#baz\) at .*/foo\.rb:18}
],
out
)
Expand Down