brew/Library/Homebrew/test/utils/backtrace_spec.rb
apainintheneck 85bd4c7e1f utils/backtrace: scrub sorbet-runtime from backtrace
Ever since we started using this at runtime it's been polluting
the backtrace output. This makes it harder to debug errors and
increases the amount of info users have to paste into the box
when filing an issue.

This is a very direct approach. Essentially, we strip out
everything related to the `sorbet-runtime` gem whenever the top
line in the backtrace is unrelated to sorbet-runtime.

The hope is that this will allow errors related to sorbet to
be diagnosed easily while also reducing the backtrace size
for all other types of errors.

Sometimes it is useful to see the full backtrace though.
For those cases, we include the full backtrace when
`--verbose` is passed in and print a warning that the
Sorbet lines have been removed from the backtrace the
first time they are removed.

Note: This requires gems to be set up so that the call to
`Gem.paths.home` works correctly. For that reason, it must
be included after `utils/gems` which is included in
`standalone/load_path` already.
2023-09-21 21:07:22 -07:00

91 lines
3.8 KiB
Ruby

# frozen_string_literal: true
require "utils/backtrace"
describe Utils::Backtrace do
let(:backtrace_no_sorbet_paths) do
[
"/Library/Homebrew/downloadable.rb:75:in",
"/Library/Homebrew/downloadable.rb:50:in",
"/Library/Homebrew/cmd/fetch.rb:236:in",
"/Library/Homebrew/cmd/fetch.rb:201:in",
"/Library/Homebrew/cmd/fetch.rb:178:in",
"/Library/Homebrew/simulate_system.rb:29:in",
"/Library/Homebrew/cmd/fetch.rb:166:in",
"/Library/Homebrew/cmd/fetch.rb:163:in",
"/Library/Homebrew/cmd/fetch.rb:163:in",
"/Library/Homebrew/cmd/fetch.rb:94:in",
"/Library/Homebrew/cmd/fetch.rb:94:in",
"/Library/Homebrew/brew.rb:94:in",
]
end
let(:backtrace_with_sorbet_paths) do
[
"/Library/Homebrew/downloadable.rb:75:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/_methods.rb:270:in",
"/Library/Homebrew/downloadable.rb:50:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/_methods.rb:270:in",
"/Library/Homebrew/cmd/fetch.rb:236:in",
"/Library/Homebrew/cmd/fetch.rb:201:in",
"/Library/Homebrew/cmd/fetch.rb:178:in",
"/Library/Homebrew/simulate_system.rb:29:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/call_validation.rb:157:in",
"/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime-0.5.10461/lib/_methods.rb:270:in",
"/Library/Homebrew/cmd/fetch.rb:166:in",
"/Library/Homebrew/cmd/fetch.rb:163:in",
"/Library/Homebrew/cmd/fetch.rb:163:in",
"/Library/Homebrew/cmd/fetch.rb:94:in",
"/Library/Homebrew/cmd/fetch.rb:94:in",
"/Library/Homebrew/brew.rb:94:in",
]
end
let(:backtrace_with_sorbet_error) do
backtrace_with_sorbet_paths.drop(1)
end
def exception_with(backtrace:)
exception = StandardError.new
exception.set_backtrace(backtrace) if backtrace
exception
end
before do
allow(described_class).to receive(:sorbet_runtime_path)
.and_return("/Library/Homebrew/vendor/bundle/ruby/2.6.0/gems/sorbet-runtime")
allow(Context).to receive(:current).and_return(Context::ContextStruct.new(verbose: false))
end
it "handles nil backtrace" do
exception = exception_with backtrace: nil
expect(described_class.clean(exception)).to be_nil
end
it "handles empty array backtrace" do
exception = exception_with backtrace: []
expect(described_class.clean(exception)).to eq []
end
it "removes sorbet paths when top error is not from sorbet" do
exception = exception_with backtrace: backtrace_with_sorbet_paths
expect(described_class.clean(exception)).to eq backtrace_no_sorbet_paths
end
it "includes sorbet paths when top error is not from sorbet and verbose is set" do
allow(Context).to receive(:current).and_return(Context::ContextStruct.new(verbose: true))
exception = exception_with backtrace: backtrace_with_sorbet_paths
expect(described_class.clean(exception)).to eq backtrace_with_sorbet_paths
end
it "doesn't change backtrace when error is from sorbet" do
exception = exception_with backtrace: backtrace_with_sorbet_error
expect(described_class.clean(exception)).to eq backtrace_with_sorbet_error
end
end