From 57f5746d6e034e703a76d14d5b46a3d2a9b81c33 Mon Sep 17 00:00:00 2001 From: Sijawusz Pur Rahnama Date: Fri, 1 Jan 2021 16:12:57 +0100 Subject: [PATCH] Extend specs coverage --- .../backtracer/backtrace/frame/parser_spec.cr | 202 +++++++++++++++++ spec/backtracer/backtrace/frame_spec.cr | 207 +----------------- spec/backtracer/backtrace/parser_spec.cr | 33 +++ spec/backtracer/backtrace_spec.cr | 25 ++- spec/backtracer/configuration_spec.cr | 4 - spec/spec_helper.cr | 34 +++ 6 files changed, 287 insertions(+), 218 deletions(-) create mode 100644 spec/backtracer/backtrace/frame/parser_spec.cr create mode 100644 spec/backtracer/backtrace/parser_spec.cr diff --git a/spec/backtracer/backtrace/frame/parser_spec.cr b/spec/backtracer/backtrace/frame/parser_spec.cr new file mode 100644 index 0000000..7df2f9e --- /dev/null +++ b/spec/backtracer/backtrace/frame/parser_spec.cr @@ -0,0 +1,202 @@ +require "../../../spec_helper" + +describe Backtracer::Backtrace::Frame::Parser do + describe ".parse" do + it "fails to parse an empty string" do + expect_raises(ArgumentError) { with_frame("", &.itself) } + end + + context "when --no-debug flag is set" do + it "parses frame with any value as method" do + backtrace_line = "__crystal_main" + + with_frame(backtrace_line) do |frame| + frame.lineno.should be_nil + frame.column.should be_nil + frame.method.should eq(backtrace_line) + frame.path.should be_nil + frame.relative_path.should be_nil + frame.under_src_path?.should be_false + frame.shard_name.should be_nil + frame.in_app?.should be_false + end + end + end + + context "with ~proc signature" do + it "parses absolute path outside of src/ dir" do + path = "/usr/local/Cellar/crystal/0.27.2/src/fiber.cr" + backtrace_line = "~proc2Proc(Fiber, (IO::FileDescriptor | Nil))@#{path}:72" + + with_frame(backtrace_line) do |frame| + frame.lineno.should eq(72) + frame.column.should be_nil + frame.method.should eq("~proc2Proc(Fiber, (IO::FileDescriptor | Nil))") + frame.path.should eq(path) + frame.absolute_path.should eq(frame.path) + frame.relative_path.should be_nil + frame.under_src_path?.should be_false + frame.shard_name.should be_nil + frame.in_app?.should be_false + end + end + + it "parses relative path inside of lib/ dir" do + with_configuration do |configuration| + path = "lib/kemal/src/kemal/route.cr" + backtrace_line = "~procProc(HTTP::Server::Context, String)@#{path}:11" + + with_frame(backtrace_line) do |frame| + frame.lineno.should eq(11) + frame.column.should be_nil + frame.method.should eq("~procProc(HTTP::Server::Context, String)") + frame.path.should eq(path) + frame.absolute_path.should eq( + File.join(configuration.src_path.not_nil!, path) + ) + frame.relative_path.should eq(frame.path) + frame.under_src_path?.should be_false + frame.shard_name.should eq("kemal") + frame.in_app?.should be_false + end + end + end + end + + it "parses absolute path outside of configuration.src_path" do + path = "/some/absolute/path/to/foo.cr" + + with_foo_frame(path: path) do |frame| + frame.lineno.should eq(1) + frame.column.should eq(7) + frame.method.should eq("foo_bar?") + frame.path.should eq(path) + frame.absolute_path.should eq(frame.path) + frame.relative_path.should be_nil + frame.under_src_path?.should be_false + frame.shard_name.should be_nil + frame.in_app?.should be_false + end + end + + context "with in_app? = false" do + it "parses absolute path outside of src/ dir" do + with_foo_frame(path: "#{__DIR__}/foo.cr") do |frame| + frame.lineno.should eq(1) + frame.column.should eq(7) + frame.method.should eq("foo_bar?") + frame.path.should eq("#{__DIR__}/foo.cr") + frame.absolute_path.should eq(frame.path) + frame.relative_path.should eq("spec/backtracer/backtrace/frame/foo.cr") + frame.under_src_path?.should be_true + frame.shard_name.should be_nil + frame.in_app?.should be_false + end + end + + it "parses relative path outside of src/ dir" do + with_configuration do |configuration| + path = "some/relative/path/to/foo.cr" + + with_foo_frame(path: path) do |frame| + frame.lineno.should eq(1) + frame.column.should eq(7) + frame.method.should eq("foo_bar?") + frame.path.should eq(path) + frame.absolute_path.should eq( + File.join(configuration.src_path.not_nil!, path) + ) + frame.relative_path.should eq(frame.path) + frame.under_src_path?.should be_false + frame.shard_name.should be_nil + frame.in_app?.should be_false + end + end + end + end + + context "with in_app? = true" do + it "parses absolute path inside of src/ dir" do + src_path = File.expand_path("../../../../src", __DIR__) + path = "#{src_path}/foo.cr" + + with_foo_frame(path: path) do |frame| + frame.lineno.should eq(1) + frame.column.should eq(7) + frame.method.should eq("foo_bar?") + frame.path.should eq(path) + frame.absolute_path.should eq(frame.path) + frame.relative_path.should eq("src/foo.cr") + frame.under_src_path?.should be_true + frame.shard_name.should be_nil + frame.in_app?.should be_true + end + end + + it "parses relative path inside of src/ dir" do + with_configuration do |configuration| + path = "src/foo.cr" + + with_foo_frame(path: path) do |frame| + frame.lineno.should eq(1) + frame.column.should eq(7) + frame.method.should eq("foo_bar?") + frame.path.should eq(path) + frame.absolute_path.should eq( + File.join(configuration.src_path.not_nil!, path) + ) + frame.relative_path.should eq(path) + frame.under_src_path?.should be_false + frame.shard_name.should be_nil + frame.in_app?.should be_true + end + end + end + end + + context "with shard path" do + it "parses absolute path inside of lib/ dir" do + lib_path = File.expand_path("../../../../lib/bar", __DIR__) + path = "#{lib_path}/src/bar.cr" + + with_foo_frame(path: path) do |frame| + frame.lineno.should eq(1) + frame.column.should eq(7) + frame.method.should eq("foo_bar?") + frame.path.should eq(path) + frame.absolute_path.should eq(frame.path) + frame.relative_path.should eq("lib/bar/src/bar.cr") + frame.under_src_path?.should be_true + frame.shard_name.should eq "bar" + frame.in_app?.should be_false + end + end + + it "parses relative path inside of lib/ dir" do + with_configuration do |configuration| + path = "lib/bar/src/bar.cr" + + with_foo_frame(path: path) do |frame| + frame.lineno.should eq(1) + frame.column.should eq(7) + frame.method.should eq("foo_bar?") + frame.path.should eq(path) + frame.absolute_path.should eq( + File.join(configuration.src_path.not_nil!, path) + ) + frame.relative_path.should eq(path) + frame.under_src_path?.should be_false + frame.shard_name.should eq "bar" + frame.in_app?.should be_false + end + end + end + + it "uses only folders for shard names" do + with_foo_frame(path: "lib/bar.cr") do |frame| + frame.shard_name.should be_nil + end + end + end + end +end diff --git a/spec/backtracer/backtrace/frame_spec.cr b/spec/backtracer/backtrace/frame_spec.cr index 5f6032c..ac355da 100644 --- a/spec/backtracer/backtrace/frame_spec.cr +++ b/spec/backtracer/backtrace/frame_spec.cr @@ -1,207 +1,6 @@ require "../../spec_helper" -private def parse_frame(line) - Backtracer::Backtrace::Frame::Parser.parse(line) -end - -private def with_frame(method, path = nil, lineno = nil, column = nil) - line = String.build do |io| - if path - io << path - io << ':' << lineno if lineno - io << ':' << column if column - io << " in '" << method << '\'' - else - io << method - end - end - yield parse_frame(line) -end - -private def with_foo_frame( - method = "foo_bar?", - path = "#{__DIR__}/foo.cr", - lineno = 1, - column = 7 -) - with_frame(method, path, lineno, column) do |frame| - yield frame - end -end - describe Backtracer::Backtrace::Frame do - describe ".parse" do - it "fails to parse an empty string" do - expect_raises(ArgumentError) { parse_frame("") } - end - - context "when --no-debug flag is set" do - it "parses frame with any value as method" do - backtrace_line = "__crystal_main" - - with_frame(backtrace_line) do |frame| - frame.lineno.should be_nil - frame.column.should be_nil - frame.method.should eq(backtrace_line) - frame.path.should be_nil - frame.relative_path.should be_nil - frame.under_src_path?.should be_false - frame.shard_name.should be_nil - frame.in_app?.should be_false - end - end - end - - context "with ~proc signature" do - it "parses absolute path outside of src/ dir" do - backtrace_line = "~proc2Proc(Fiber, (IO::FileDescriptor | Nil))@/usr/local/Cellar/crystal/0.27.2/src/fiber.cr:72" - - with_frame(backtrace_line) do |frame| - frame.lineno.should eq(72) - frame.column.should be_nil - frame.method.should eq("~proc2Proc(Fiber, (IO::FileDescriptor | Nil))") - frame.path.should eq("/usr/local/Cellar/crystal/0.27.2/src/fiber.cr") - frame.relative_path.should be_nil - frame.under_src_path?.should be_false - frame.shard_name.should be_nil - frame.in_app?.should be_false - end - end - - it "parses relative path inside of lib/ dir" do - backtrace_line = "~procProc(HTTP::Server::Context, String)@lib/kemal/src/kemal/route.cr:11" - - with_frame(backtrace_line) do |frame| - frame.lineno.should eq(11) - frame.column.should be_nil - frame.method.should eq("~procProc(HTTP::Server::Context, String)") - frame.path.should eq("lib/kemal/src/kemal/route.cr") - frame.relative_path.should eq("lib/kemal/src/kemal/route.cr") - frame.under_src_path?.should be_false - frame.shard_name.should eq("kemal") - frame.in_app?.should be_false - end - end - end - - it "parses absolute path outside of configuration.src_path" do - path = "/some/absolute/path/to/foo.cr" - - with_foo_frame(path: path) do |frame| - frame.lineno.should eq(1) - frame.column.should eq(7) - frame.method.should eq("foo_bar?") - frame.path.should eq(path) - frame.relative_path.should be_nil - frame.under_src_path?.should be_false - frame.shard_name.should be_nil - frame.in_app?.should be_false - end - end - - context "with in_app? = false" do - it "parses absolute path outside of src/ dir" do - with_foo_frame do |frame| - frame.lineno.should eq(1) - frame.column.should eq(7) - frame.method.should eq("foo_bar?") - frame.path.should eq("#{__DIR__}/foo.cr") - frame.relative_path.should eq("spec/backtracer/backtrace/foo.cr") - frame.under_src_path?.should be_true - frame.shard_name.should be_nil - frame.in_app?.should be_false - end - end - - it "parses relative path outside of src/ dir" do - path = "some/relative/path/to/foo.cr" - - with_foo_frame(path: path) do |frame| - frame.lineno.should eq(1) - frame.column.should eq(7) - frame.method.should eq("foo_bar?") - frame.path.should eq(path) - frame.relative_path.should eq(path) - frame.under_src_path?.should be_false - frame.shard_name.should be_nil - frame.in_app?.should be_false - end - end - end - - context "with in_app? = true" do - it "parses absolute path inside of src/ dir" do - src_path = File.expand_path("../../../src", __DIR__) - path = "#{src_path}/foo.cr" - - with_foo_frame(path: path) do |frame| - frame.lineno.should eq(1) - frame.column.should eq(7) - frame.method.should eq("foo_bar?") - frame.path.should eq(path) - frame.relative_path.should eq("src/foo.cr") - frame.under_src_path?.should be_true - frame.shard_name.should be_nil - frame.in_app?.should be_true - end - end - - it "parses relative path inside of src/ dir" do - path = "src/foo.cr" - - with_foo_frame(path: path) do |frame| - frame.lineno.should eq(1) - frame.column.should eq(7) - frame.method.should eq("foo_bar?") - frame.path.should eq(path) - frame.relative_path.should eq(path) - frame.under_src_path?.should be_false - frame.shard_name.should be_nil - frame.in_app?.should be_true - end - end - end - - context "with shard path" do - it "parses absolute path inside of lib/ dir" do - lib_path = File.expand_path("../../../lib/bar", __DIR__) - path = "#{lib_path}/src/bar.cr" - - with_foo_frame(path: path) do |frame| - frame.lineno.should eq(1) - frame.column.should eq(7) - frame.method.should eq("foo_bar?") - frame.path.should eq(path) - frame.relative_path.should eq("lib/bar/src/bar.cr") - frame.under_src_path?.should be_true - frame.shard_name.should eq "bar" - frame.in_app?.should be_false - end - end - - it "parses relative path inside of lib/ dir" do - path = "lib/bar/src/bar.cr" - - with_foo_frame(path: path) do |frame| - frame.lineno.should eq(1) - frame.column.should eq(7) - frame.method.should eq("foo_bar?") - frame.path.should eq(path) - frame.relative_path.should eq(path) - frame.under_src_path?.should be_false - frame.shard_name.should eq "bar" - frame.in_app?.should be_false - end - end - - it "uses only folders for shard names" do - with_foo_frame(path: "lib/bar.cr") do |frame| - frame.shard_name.should be_nil - end - end - end - end - it "#inspect" do with_foo_frame do |frame| frame.inspect.should match(/Backtrace::Frame(.*)$/) @@ -209,7 +8,7 @@ describe Backtracer::Backtrace::Frame do end it "#to_s" do - with_foo_frame do |frame| + with_foo_frame(path: "#{__DIR__}/foo.cr") do |frame| frame.to_s.should eq "`foo_bar?` at #{__DIR__}/foo.cr:1:7" end end @@ -219,8 +18,8 @@ describe Backtracer::Backtrace::Frame do with_foo_frame do |frame2| frame.should eq(frame2) end - with_foo_frame(method: "other_method") do |frame2| - frame.should_not eq(frame2) + with_foo_frame(method: "other_method") do |frame3| + frame.should_not eq(frame3) end end end diff --git a/spec/backtracer/backtrace/parser_spec.cr b/spec/backtracer/backtrace/parser_spec.cr new file mode 100644 index 0000000..8ebbe75 --- /dev/null +++ b/spec/backtracer/backtrace/parser_spec.cr @@ -0,0 +1,33 @@ +require "../../spec_helper" + +describe Backtracer::Backtrace::Parser do + describe ".parse" do + it "handles `caller` as an input" do + with_backtrace(caller) do |backtrace| + backtrace.frames.should_not be_empty + + backtrace.frames.first + .tap(&.absolute_path.should eq(__FILE__)) + .tap(&.path.should eq("spec/backtracer/backtrace/parser_spec.cr")) + + backtrace.frames.last.method.should eq("main") + end + end + + it "handles `Exception#backtrace` as an input" do + begin + raise "Oh, no!" + rescue ex + with_backtrace(ex.backtrace) do |backtrace| + backtrace.frames.should_not be_empty + + backtrace.frames.first + .tap(&.absolute_path.should eq(__FILE__)) + .tap(&.path.should eq("spec/backtracer/backtrace/parser_spec.cr")) + + backtrace.frames.last.method.should eq("main") + end + end + end + end +end diff --git a/spec/backtracer/backtrace_spec.cr b/spec/backtracer/backtrace_spec.cr index 36bc340..3948c3e 100644 --- a/spec/backtracer/backtrace_spec.cr +++ b/spec/backtracer/backtrace_spec.cr @@ -1,24 +1,29 @@ require "../spec_helper" describe Backtracer::Backtrace do - backtrace = Backtracer.parse(caller) - it "#frames" do - backtrace.frames.should be_a(Array(Backtracer::Backtrace::Frame)) + with_backtrace(caller) do |backtrace| + backtrace.frames.should be_a(Array(Backtracer::Backtrace::Frame)) + backtrace.frames.should_not be_empty + end end it "#inspect" do - backtrace.inspect.should match(/#$/) + with_backtrace(caller) do |backtrace| + backtrace.inspect.should match(/#$/) + end end - {% unless flag?(:release) || !flag?(:debug) %} - it "#to_s" do - backtrace.to_s.should match(/backtrace_spec.cr:4/) + it "#to_s" do + with_backtrace(caller) do |backtrace| + backtrace.to_s.should match(/backtrace_spec.cr/) end - {% end %} + end it "#==" do - backtrace2 = Backtracer::Backtrace.new(backtrace.frames) - backtrace2.should eq(backtrace) + with_backtrace(caller) do |backtrace| + backtrace2 = Backtracer::Backtrace.new(backtrace.frames) + backtrace2.should eq(backtrace) + end end end diff --git a/spec/backtracer/configuration_spec.cr b/spec/backtracer/configuration_spec.cr index 76284c6..c192860 100644 --- a/spec/backtracer/configuration_spec.cr +++ b/spec/backtracer/configuration_spec.cr @@ -1,9 +1,5 @@ require "../spec_helper" -private def with_configuration - yield Backtracer::Configuration.new -end - describe Backtracer::Configuration do it "should set #src_path to current dir from default" do with_configuration do |configuration| diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index e0c7f38..11c6c86 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -1,2 +1,36 @@ require "spec" require "../src/backtracer" + +def with_configuration(shared = true) + yield shared ? Backtracer.configuration : Backtracer::Configuration.new +end + +def with_backtrace(backtrace, **options) + yield Backtracer::Backtrace::Parser.parse(backtrace, **options) +end + +def with_frame(method, path = nil, lineno = nil, column = nil, **options) + line = String.build do |io| + if path + io << path + io << ':' << lineno if lineno + io << ':' << column if column + io << " in '" << method << '\'' + else + io << method + end + end + yield Backtracer::Backtrace::Frame::Parser.parse(line, **options) +end + +def with_foo_frame( + method = "foo_bar?", + path = "#{__DIR__}/foo.cr", + lineno = 1, + column = 7, + **options +) + with_frame(method, path, lineno, column, **options) do |frame| + yield frame + end +end