better_errors 2.0.0 → 2.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|