better_errors 2.0.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.coveralls.yml +1 -0
- data/.gitignore +3 -0
- data/.travis.yml +96 -2
- data/CHANGELOG.md +1 -1
- data/Gemfile +2 -7
- data/LICENSE.txt +1 -1
- data/README.md +99 -39
- data/better_errors.gemspec +23 -4
- data/gemfiles/pry010.gemfile +9 -0
- data/gemfiles/pry011.gemfile +8 -0
- data/gemfiles/pry09.gemfile +8 -0
- data/gemfiles/rack.gemfile +7 -0
- data/gemfiles/rack_boc.gemfile +8 -0
- data/gemfiles/rails42.gemfile +9 -0
- data/gemfiles/rails42_boc.gemfile +10 -0
- data/gemfiles/rails42_haml.gemfile +10 -0
- data/gemfiles/rails50.gemfile +8 -0
- data/gemfiles/rails50_boc.gemfile +9 -0
- data/gemfiles/rails50_haml.gemfile +9 -0
- data/gemfiles/rails51.gemfile +8 -0
- data/gemfiles/rails51_boc.gemfile +9 -0
- data/gemfiles/rails51_haml.gemfile +9 -0
- data/gemfiles/rails52.gemfile +8 -0
- data/gemfiles/rails52_boc.gemfile +9 -0
- data/gemfiles/rails52_haml.gemfile +9 -0
- data/gemfiles/rails60.gemfile +7 -0
- data/gemfiles/rails60_boc.gemfile +8 -0
- data/gemfiles/rails60_haml.gemfile +8 -0
- data/lib/better_errors/code_formatter/html.rb +1 -1
- data/lib/better_errors/code_formatter.rb +7 -7
- data/lib/better_errors/error_page.rb +56 -15
- data/lib/better_errors/inspectable_value.rb +45 -0
- data/lib/better_errors/middleware.rb +96 -16
- data/lib/better_errors/raised_exception.rb +13 -3
- data/lib/better_errors/repl/basic.rb +3 -3
- data/lib/better_errors/repl/pry.rb +18 -8
- data/lib/better_errors/repl.rb +6 -4
- data/lib/better_errors/stack_frame.rb +33 -8
- data/lib/better_errors/templates/main.erb +71 -34
- data/lib/better_errors/templates/text.erb +2 -2
- data/lib/better_errors/templates/variable_info.erb +32 -23
- data/lib/better_errors/version.rb +1 -1
- data/lib/better_errors.rb +21 -3
- metadata +118 -35
- data/Rakefile +0 -13
- data/spec/better_errors/code_formatter_spec.rb +0 -92
- data/spec/better_errors/error_page_spec.rb +0 -76
- data/spec/better_errors/middleware_spec.rb +0 -154
- data/spec/better_errors/raised_exception_spec.rb +0 -52
- data/spec/better_errors/repl/basic_spec.rb +0 -18
- data/spec/better_errors/repl/pry_spec.rb +0 -40
- data/spec/better_errors/repl/shared_examples.rb +0 -18
- data/spec/better_errors/stack_frame_spec.rb +0 -157
- data/spec/better_errors/support/my_source.rb +0 -20
- data/spec/better_errors_spec.rb +0 -73
- data/spec/spec_helper.rb +0 -5
- data/spec/without_binding_of_caller.rb +0 -9
@@ -1,92 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module BetterErrors
|
4
|
-
describe CodeFormatter do
|
5
|
-
let(:filename) { File.expand_path("../support/my_source.rb", __FILE__) }
|
6
|
-
|
7
|
-
let(:formatter) { CodeFormatter.new(filename, 8) }
|
8
|
-
|
9
|
-
it "picks an appropriate scanner" do
|
10
|
-
formatter.coderay_scanner.should == :ruby
|
11
|
-
end
|
12
|
-
|
13
|
-
it "shows 5 lines of context" do
|
14
|
-
formatter.line_range.should == (3..13)
|
15
|
-
|
16
|
-
formatter.context_lines.should == [
|
17
|
-
"three\n",
|
18
|
-
"four\n",
|
19
|
-
"five\n",
|
20
|
-
"six\n",
|
21
|
-
"seven\n",
|
22
|
-
"eight\n",
|
23
|
-
"nine\n",
|
24
|
-
"ten\n",
|
25
|
-
"eleven\n",
|
26
|
-
"twelve\n",
|
27
|
-
"thirteen\n"
|
28
|
-
]
|
29
|
-
end
|
30
|
-
|
31
|
-
it "works when the line is right on the edge" do
|
32
|
-
formatter = CodeFormatter.new(filename, 20)
|
33
|
-
formatter.line_range.should == (15..20)
|
34
|
-
end
|
35
|
-
|
36
|
-
describe CodeFormatter::HTML do
|
37
|
-
it "highlights the erroring line" do
|
38
|
-
formatter = CodeFormatter::HTML.new(filename, 8)
|
39
|
-
formatter.output.should =~ /highlight.*eight/
|
40
|
-
end
|
41
|
-
|
42
|
-
it "works when the line is right on the edge" do
|
43
|
-
formatter = CodeFormatter::HTML.new(filename, 20)
|
44
|
-
formatter.output.should_not == formatter.source_unavailable
|
45
|
-
end
|
46
|
-
|
47
|
-
it "doesn't barf when the lines don't make any sense" do
|
48
|
-
formatter = CodeFormatter::HTML.new(filename, 999)
|
49
|
-
formatter.output.should == formatter.source_unavailable
|
50
|
-
end
|
51
|
-
|
52
|
-
it "doesn't barf when the file doesn't exist" do
|
53
|
-
formatter = CodeFormatter::HTML.new("fkdguhskd7e l", 1)
|
54
|
-
formatter.output.should == formatter.source_unavailable
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
describe CodeFormatter::Text do
|
59
|
-
it "highlights the erroring line" do
|
60
|
-
formatter = CodeFormatter::Text.new(filename, 8)
|
61
|
-
formatter.output.should == <<-TEXT.gsub(/^ /, "")
|
62
|
-
3 three
|
63
|
-
4 four
|
64
|
-
5 five
|
65
|
-
6 six
|
66
|
-
7 seven
|
67
|
-
> 8 eight
|
68
|
-
9 nine
|
69
|
-
10 ten
|
70
|
-
11 eleven
|
71
|
-
12 twelve
|
72
|
-
13 thirteen
|
73
|
-
TEXT
|
74
|
-
end
|
75
|
-
|
76
|
-
it "works when the line is right on the edge" do
|
77
|
-
formatter = CodeFormatter::Text.new(filename, 20)
|
78
|
-
formatter.output.should_not == formatter.source_unavailable
|
79
|
-
end
|
80
|
-
|
81
|
-
it "doesn't barf when the lines don't make any sense" do
|
82
|
-
formatter = CodeFormatter::Text.new(filename, 999)
|
83
|
-
formatter.output.should == formatter.source_unavailable
|
84
|
-
end
|
85
|
-
|
86
|
-
it "doesn't barf when the file doesn't exist" do
|
87
|
-
formatter = CodeFormatter::Text.new("fkdguhskd7e l", 1)
|
88
|
-
formatter.output.should == formatter.source_unavailable
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module BetterErrors
|
4
|
-
describe ErrorPage do
|
5
|
-
let!(:exception) { raise ZeroDivisionError, "you divided by zero you silly goose!" rescue $! }
|
6
|
-
|
7
|
-
let(:error_page) { ErrorPage.new exception, { "PATH_INFO" => "/some/path" } }
|
8
|
-
|
9
|
-
let(:response) { error_page.render }
|
10
|
-
|
11
|
-
let(:empty_binding) {
|
12
|
-
local_a = :value_for_local_a
|
13
|
-
local_b = :value_for_local_b
|
14
|
-
|
15
|
-
@inst_c = :value_for_inst_c
|
16
|
-
@inst_d = :value_for_inst_d
|
17
|
-
|
18
|
-
binding
|
19
|
-
}
|
20
|
-
|
21
|
-
it "includes the error message" do
|
22
|
-
response.should include("you divided by zero you silly goose!")
|
23
|
-
end
|
24
|
-
|
25
|
-
it "includes the request path" do
|
26
|
-
response.should include("/some/path")
|
27
|
-
end
|
28
|
-
|
29
|
-
it "includes the exception class" do
|
30
|
-
response.should include("ZeroDivisionError")
|
31
|
-
end
|
32
|
-
|
33
|
-
context "variable inspection" do
|
34
|
-
let(:exception) { empty_binding.eval("raise") rescue $! }
|
35
|
-
|
36
|
-
if BetterErrors.binding_of_caller_available?
|
37
|
-
it "shows local variables" do
|
38
|
-
html = error_page.do_variables("index" => 0)[:html]
|
39
|
-
html.should include("local_a")
|
40
|
-
html.should include(":value_for_local_a")
|
41
|
-
html.should include("local_b")
|
42
|
-
html.should include(":value_for_local_b")
|
43
|
-
end
|
44
|
-
else
|
45
|
-
it "tells the user to add binding_of_caller to their gemfile to get fancy features" do
|
46
|
-
html = error_page.do_variables("index" => 0)[:html]
|
47
|
-
html.should include(%{gem "binding_of_caller"})
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
it "shows instance variables" do
|
52
|
-
html = error_page.do_variables("index" => 0)[:html]
|
53
|
-
html.should include("inst_c")
|
54
|
-
html.should include(":value_for_inst_c")
|
55
|
-
html.should include("inst_d")
|
56
|
-
html.should include(":value_for_inst_d")
|
57
|
-
end
|
58
|
-
|
59
|
-
it "shows filter instance variables" do
|
60
|
-
BetterErrors.stub(:ignored_instance_variables).and_return([ :@inst_d ])
|
61
|
-
html = error_page.do_variables("index" => 0)[:html]
|
62
|
-
html.should include("inst_c")
|
63
|
-
html.should include(":value_for_inst_c")
|
64
|
-
html.should_not include('<td class="name">@inst_d</td>')
|
65
|
-
html.should_not include("<pre>:value_for_inst_d</pre>")
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
it "doesn't die if the source file is not a real filename" do
|
70
|
-
exception.stub(:backtrace).and_return([
|
71
|
-
"<internal:prelude>:10:in `spawn_rack_application'"
|
72
|
-
])
|
73
|
-
response.should include("Source unavailable")
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,154 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module BetterErrors
|
4
|
-
describe Middleware do
|
5
|
-
let(:app) { Middleware.new(->env { ":)" }) }
|
6
|
-
let(:exception) { RuntimeError.new("oh no :(") }
|
7
|
-
|
8
|
-
it "passes non-error responses through" do
|
9
|
-
app.call({}).should == ":)"
|
10
|
-
end
|
11
|
-
|
12
|
-
it "calls the internal methods" do
|
13
|
-
app.should_receive :internal_call
|
14
|
-
app.call("PATH_INFO" => "/__better_errors/1/preform_awesomness")
|
15
|
-
end
|
16
|
-
|
17
|
-
it "calls the internal methods on any subfolder path" do
|
18
|
-
app.should_receive :internal_call
|
19
|
-
app.call("PATH_INFO" => "/any_sub/folder/path/__better_errors/1/preform_awesomness")
|
20
|
-
end
|
21
|
-
|
22
|
-
it "shows the error page" do
|
23
|
-
app.should_receive :show_error_page
|
24
|
-
app.call("PATH_INFO" => "/__better_errors/")
|
25
|
-
end
|
26
|
-
|
27
|
-
it "shows the error page on any subfolder path" do
|
28
|
-
app.should_receive :show_error_page
|
29
|
-
app.call("PATH_INFO" => "/any_sub/folder/path/__better_errors/")
|
30
|
-
end
|
31
|
-
|
32
|
-
it "doesn't show the error page to a non-local address" do
|
33
|
-
app.should_not_receive :better_errors_call
|
34
|
-
app.call("REMOTE_ADDR" => "1.2.3.4")
|
35
|
-
end
|
36
|
-
|
37
|
-
it "shows to a whitelisted IP" do
|
38
|
-
BetterErrors::Middleware.allow_ip! '77.55.33.11'
|
39
|
-
app.should_receive :better_errors_call
|
40
|
-
app.call("REMOTE_ADDR" => "77.55.33.11")
|
41
|
-
end
|
42
|
-
|
43
|
-
it "respects the X-Forwarded-For header" do
|
44
|
-
app.should_not_receive :better_errors_call
|
45
|
-
app.call(
|
46
|
-
"REMOTE_ADDR" => "127.0.0.1",
|
47
|
-
"HTTP_X_FORWARDED_FOR" => "1.2.3.4",
|
48
|
-
)
|
49
|
-
end
|
50
|
-
|
51
|
-
it "doesn't blow up when given a blank REMOTE_ADDR" do
|
52
|
-
expect { app.call("REMOTE_ADDR" => " ") }.to_not raise_error
|
53
|
-
end
|
54
|
-
|
55
|
-
it "doesn't blow up when given an IP address with a zone index" do
|
56
|
-
expect { app.call("REMOTE_ADDR" => "0:0:0:0:0:0:0:1%0" ) }.to_not raise_error
|
57
|
-
end
|
58
|
-
|
59
|
-
context "when requesting the /__better_errors manually" do
|
60
|
-
let(:app) { Middleware.new(->env { ":)" }) }
|
61
|
-
|
62
|
-
it "shows that no errors have been recorded" do
|
63
|
-
status, headers, body = app.call("PATH_INFO" => "/__better_errors")
|
64
|
-
body.join.should match /No errors have been recorded yet./
|
65
|
-
end
|
66
|
-
|
67
|
-
it "shows that no errors have been recorded on any subfolder path" do
|
68
|
-
status, headers, body = app.call("PATH_INFO" => "/any_sub/folder/path/__better_errors")
|
69
|
-
body.join.should match /No errors have been recorded yet./
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
context "when handling an error" do
|
74
|
-
let(:app) { Middleware.new(->env { raise exception }) }
|
75
|
-
|
76
|
-
it "returns status 500" do
|
77
|
-
status, headers, body = app.call({})
|
78
|
-
|
79
|
-
status.should == 500
|
80
|
-
end
|
81
|
-
|
82
|
-
context "original_exception" do
|
83
|
-
class OriginalExceptionException < Exception
|
84
|
-
attr_reader :original_exception
|
85
|
-
|
86
|
-
def initialize(message, original_exception = nil)
|
87
|
-
super(message)
|
88
|
-
@original_exception = original_exception
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
it "shows Original Exception if it responds_to and has an original_exception" do
|
93
|
-
app = Middleware.new(->env {
|
94
|
-
raise OriginalExceptionException.new("Other Exception", Exception.new("Original Exception"))
|
95
|
-
})
|
96
|
-
|
97
|
-
status, _, body = app.call({})
|
98
|
-
|
99
|
-
status.should == 500
|
100
|
-
body.join.should_not match(/Other Exception/)
|
101
|
-
body.join.should match(/Original Exception/)
|
102
|
-
end
|
103
|
-
|
104
|
-
it "won't crash if the exception responds_to but doesn't have an original_exception" do
|
105
|
-
app = Middleware.new(->env {
|
106
|
-
raise OriginalExceptionException.new("Other Exception")
|
107
|
-
})
|
108
|
-
|
109
|
-
status, _, body = app.call({})
|
110
|
-
|
111
|
-
status.should == 500
|
112
|
-
body.join.should match(/Other Exception/)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
it "returns ExceptionWrapper's status_code" do
|
117
|
-
ad_ew = double("ActionDispatch::ExceptionWrapper")
|
118
|
-
ad_ew.stub('new').with({}, exception ){ double("ExceptionWrapper", status_code: 404) }
|
119
|
-
stub_const('ActionDispatch::ExceptionWrapper', ad_ew)
|
120
|
-
|
121
|
-
status, headers, body = app.call({})
|
122
|
-
|
123
|
-
status.should == 404
|
124
|
-
end
|
125
|
-
|
126
|
-
it "returns UTF-8 error pages" do
|
127
|
-
status, headers, body = app.call({})
|
128
|
-
|
129
|
-
headers["Content-Type"].should match /charset=utf-8/
|
130
|
-
end
|
131
|
-
|
132
|
-
it "returns text pages by default" do
|
133
|
-
status, headers, body = app.call({})
|
134
|
-
|
135
|
-
headers["Content-Type"].should match /text\/plain/
|
136
|
-
end
|
137
|
-
|
138
|
-
it "returns HTML pages by default" do
|
139
|
-
# Chrome's 'Accept' header looks similar this.
|
140
|
-
status, headers, body = app.call("HTTP_ACCEPT" => "text/html,application/xhtml+xml;q=0.9,*/*")
|
141
|
-
|
142
|
-
headers["Content-Type"].should match /text\/html/
|
143
|
-
end
|
144
|
-
|
145
|
-
it "logs the exception" do
|
146
|
-
logger = Object.new
|
147
|
-
logger.should_receive :fatal
|
148
|
-
BetterErrors.stub(:logger).and_return(logger)
|
149
|
-
|
150
|
-
app.call({})
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module BetterErrors
|
4
|
-
describe RaisedException do
|
5
|
-
let(:exception) { RuntimeError.new("whoops") }
|
6
|
-
subject { RaisedException.new(exception) }
|
7
|
-
|
8
|
-
its(:exception) { should == exception }
|
9
|
-
its(:message) { should == "whoops" }
|
10
|
-
its(:type) { should == RuntimeError }
|
11
|
-
|
12
|
-
context "when the exception wraps another exception" do
|
13
|
-
let(:original_exception) { RuntimeError.new("something went wrong!") }
|
14
|
-
let(:exception) { double(:original_exception => original_exception) }
|
15
|
-
|
16
|
-
its(:exception) { should == original_exception }
|
17
|
-
its(:message) { should == "something went wrong!" }
|
18
|
-
end
|
19
|
-
|
20
|
-
context "when the exception is a syntax error" do
|
21
|
-
let(:exception) { SyntaxError.new("foo.rb:123: you made a typo!") }
|
22
|
-
|
23
|
-
its(:message) { should == "you made a typo!" }
|
24
|
-
its(:type) { should == SyntaxError }
|
25
|
-
|
26
|
-
it "has the right filename and line number in the backtrace" do
|
27
|
-
subject.backtrace.first.filename.should == "foo.rb"
|
28
|
-
subject.backtrace.first.line.should == 123
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context "when the exception is a HAML syntax error" do
|
33
|
-
before do
|
34
|
-
stub_const("Haml::SyntaxError", Class.new(SyntaxError))
|
35
|
-
end
|
36
|
-
|
37
|
-
let(:exception) {
|
38
|
-
Haml::SyntaxError.new("you made a typo!").tap do |ex|
|
39
|
-
ex.set_backtrace(["foo.rb:123", "haml/internals/blah.rb:123456"])
|
40
|
-
end
|
41
|
-
}
|
42
|
-
|
43
|
-
its(:message) { should == "you made a typo!" }
|
44
|
-
its(:type) { should == Haml::SyntaxError }
|
45
|
-
|
46
|
-
it "has the right filename and line number in the backtrace" do
|
47
|
-
subject.backtrace.first.filename.should == "foo.rb"
|
48
|
-
subject.backtrace.first.line.should == 123
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "better_errors/repl/basic"
|
3
|
-
require "better_errors/repl/shared_examples"
|
4
|
-
|
5
|
-
module BetterErrors
|
6
|
-
module REPL
|
7
|
-
describe Basic do
|
8
|
-
let(:fresh_binding) {
|
9
|
-
local_a = 123
|
10
|
-
binding
|
11
|
-
}
|
12
|
-
|
13
|
-
let(:repl) { Basic.new fresh_binding }
|
14
|
-
|
15
|
-
it_behaves_like "a REPL provider"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "pry"
|
3
|
-
require "better_errors/repl/pry"
|
4
|
-
require "better_errors/repl/shared_examples"
|
5
|
-
|
6
|
-
module BetterErrors
|
7
|
-
module REPL
|
8
|
-
describe Pry do
|
9
|
-
let(:fresh_binding) {
|
10
|
-
local_a = 123
|
11
|
-
binding
|
12
|
-
}
|
13
|
-
|
14
|
-
let(:repl) { Pry.new fresh_binding }
|
15
|
-
|
16
|
-
it "does line continuation" do
|
17
|
-
output, prompt, filled = repl.send_input ""
|
18
|
-
output.should == "=> nil\n"
|
19
|
-
prompt.should == ">>"
|
20
|
-
filled.should == ""
|
21
|
-
|
22
|
-
output, prompt, filled = repl.send_input "def f(x)"
|
23
|
-
output.should == ""
|
24
|
-
prompt.should == ".."
|
25
|
-
filled.should == " "
|
26
|
-
|
27
|
-
output, prompt, filled = repl.send_input "end"
|
28
|
-
if RUBY_VERSION >= "2.1.0"
|
29
|
-
output.should == "=> :f\n"
|
30
|
-
else
|
31
|
-
output.should == "=> nil\n"
|
32
|
-
end
|
33
|
-
prompt.should == ">>"
|
34
|
-
filled.should == ""
|
35
|
-
end
|
36
|
-
|
37
|
-
it_behaves_like "a REPL provider"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
shared_examples_for "a REPL provider" do
|
2
|
-
it "evaluates ruby code in a given context" do
|
3
|
-
repl.send_input("local_a = 456")
|
4
|
-
fresh_binding.eval("local_a").should == 456
|
5
|
-
end
|
6
|
-
|
7
|
-
it "returns a tuple of output and the new prompt" do
|
8
|
-
output, prompt = repl.send_input("1 + 2")
|
9
|
-
output.should == "=> 3\n"
|
10
|
-
prompt.should == ">>"
|
11
|
-
end
|
12
|
-
|
13
|
-
it "doesn't barf if the code throws an exception" do
|
14
|
-
output, prompt = repl.send_input("raise Exception")
|
15
|
-
output.should include "Exception: Exception"
|
16
|
-
prompt.should == ">>"
|
17
|
-
end
|
18
|
-
end
|
@@ -1,157 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
module BetterErrors
|
4
|
-
describe StackFrame do
|
5
|
-
context "#application?" do
|
6
|
-
it "is true for application filenames" do
|
7
|
-
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
8
|
-
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
|
9
|
-
|
10
|
-
frame.application?.should be_true
|
11
|
-
end
|
12
|
-
|
13
|
-
it "is false for everything else" do
|
14
|
-
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
15
|
-
frame = StackFrame.new("/abc/nope", 123, "foo")
|
16
|
-
|
17
|
-
frame.application?.should be_false
|
18
|
-
end
|
19
|
-
|
20
|
-
it "doesn't care if no application_root is set" do
|
21
|
-
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
|
22
|
-
|
23
|
-
frame.application?.should be_false
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
context "#gem?" do
|
28
|
-
it "is true for gem filenames" do
|
29
|
-
Gem.stub(:path).and_return(["/abc/xyz"])
|
30
|
-
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
|
31
|
-
|
32
|
-
frame.gem?.should be_true
|
33
|
-
end
|
34
|
-
|
35
|
-
it "is false for everything else" do
|
36
|
-
Gem.stub(:path).and_return(["/abc/xyz"])
|
37
|
-
frame = StackFrame.new("/abc/nope", 123, "foo")
|
38
|
-
|
39
|
-
frame.gem?.should be_false
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context "#application_path" do
|
44
|
-
it "chops off the application root" do
|
45
|
-
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
46
|
-
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
|
47
|
-
|
48
|
-
frame.application_path.should == "app/controllers/crap_controller.rb"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context "#gem_path" do
|
53
|
-
it "chops of the gem path and stick (gem) there" do
|
54
|
-
Gem.stub(:path).and_return(["/abc/xyz"])
|
55
|
-
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
|
56
|
-
|
57
|
-
frame.gem_path.should == "whatever (1.2.3) lib/whatever.rb"
|
58
|
-
end
|
59
|
-
|
60
|
-
it "prioritizes gem path over application path" do
|
61
|
-
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
62
|
-
Gem.stub(:path).and_return(["/abc/xyz/vendor"])
|
63
|
-
frame = StackFrame.new("/abc/xyz/vendor/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
|
64
|
-
|
65
|
-
frame.gem_path.should == "whatever (1.2.3) lib/whatever.rb"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
context "#pretty_path" do
|
70
|
-
it "returns #application_path for application paths" do
|
71
|
-
BetterErrors.stub(:application_root).and_return("/abc/xyz")
|
72
|
-
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
|
73
|
-
frame.pretty_path.should == frame.application_path
|
74
|
-
end
|
75
|
-
|
76
|
-
it "returns #gem_path for gem paths" do
|
77
|
-
Gem.stub(:path).and_return(["/abc/xyz"])
|
78
|
-
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
|
79
|
-
|
80
|
-
frame.pretty_path.should == frame.gem_path
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
it "special cases SyntaxErrors" do
|
85
|
-
begin
|
86
|
-
eval(%{ raise SyntaxError, "you wrote bad ruby!" }, nil, "my_file.rb", 123)
|
87
|
-
rescue SyntaxError => syntax_error
|
88
|
-
end
|
89
|
-
frames = StackFrame.from_exception(syntax_error)
|
90
|
-
frames.first.filename.should == "my_file.rb"
|
91
|
-
frames.first.line.should == 123
|
92
|
-
end
|
93
|
-
|
94
|
-
it "doesn't blow up if no method name is given" do
|
95
|
-
error = StandardError.allocate
|
96
|
-
|
97
|
-
error.stub(:backtrace).and_return(["foo.rb:123"])
|
98
|
-
frames = StackFrame.from_exception(error)
|
99
|
-
frames.first.filename.should == "foo.rb"
|
100
|
-
frames.first.line.should == 123
|
101
|
-
|
102
|
-
error.stub(:backtrace).and_return(["foo.rb:123: this is an error message"])
|
103
|
-
frames = StackFrame.from_exception(error)
|
104
|
-
frames.first.filename.should == "foo.rb"
|
105
|
-
frames.first.line.should == 123
|
106
|
-
end
|
107
|
-
|
108
|
-
it "ignores a backtrace line if its format doesn't make any sense at all" do
|
109
|
-
error = StandardError.allocate
|
110
|
-
error.stub(:backtrace).and_return(["foo.rb:123:in `foo'", "C:in `find'", "bar.rb:123:in `bar'"])
|
111
|
-
frames = StackFrame.from_exception(error)
|
112
|
-
frames.count.should == 2
|
113
|
-
end
|
114
|
-
|
115
|
-
it "doesn't blow up if a filename contains a colon" do
|
116
|
-
error = StandardError.allocate
|
117
|
-
error.stub(:backtrace).and_return(["crap:filename.rb:123"])
|
118
|
-
frames = StackFrame.from_exception(error)
|
119
|
-
frames.first.filename.should == "crap:filename.rb"
|
120
|
-
end
|
121
|
-
|
122
|
-
it "doesn't blow up with a BasicObject as frame binding" do
|
123
|
-
obj = BasicObject.new
|
124
|
-
def obj.my_binding
|
125
|
-
::Kernel.binding
|
126
|
-
end
|
127
|
-
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index", obj.my_binding)
|
128
|
-
frame.class_name.should == 'BasicObject'
|
129
|
-
end
|
130
|
-
|
131
|
-
it "sets method names properly" do
|
132
|
-
obj = "string"
|
133
|
-
def obj.my_method
|
134
|
-
begin
|
135
|
-
raise "foo"
|
136
|
-
rescue => err
|
137
|
-
err
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
frame = StackFrame.from_exception(obj.my_method).first
|
142
|
-
if BetterErrors.binding_of_caller_available?
|
143
|
-
frame.method_name.should == "#my_method"
|
144
|
-
frame.class_name.should == "String"
|
145
|
-
else
|
146
|
-
frame.method_name.should == "my_method"
|
147
|
-
frame.class_name.should == nil
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
if RUBY_ENGINE == "java"
|
152
|
-
it "doesn't blow up on a native Java exception" do
|
153
|
-
expect { StackFrame.from_exception(java.lang.Exception.new) }.to_not raise_error
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|