/
stack_frame_spec.rb
177 lines (145 loc) · 6.43 KB
/
stack_frame_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
require "spec_helper"
module BetterErrors
describe StackFrame do
context "#application?" do
it "is true for application filenames" do
allow(BetterErrors).to receive(:application_root).and_return("/abc/xyz")
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
expect(frame).to be_application
end
it "is false for everything else" do
allow(BetterErrors).to receive(:application_root).and_return("/abc/xyz")
frame = StackFrame.new("/abc/nope", 123, "foo")
expect(frame).not_to be_application
end
it "doesn't care if no application_root is set" do
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
expect(frame).not_to be_application
end
end
context "#gem?" do
it "is true for gem filenames" do
allow(Gem).to receive(:path).and_return(["/abc/xyz"])
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
expect(frame).to be_gem
end
it "is false for everything else" do
allow(Gem).to receive(:path).and_return(["/abc/xyz"])
frame = StackFrame.new("/abc/nope", 123, "foo")
expect(frame).not_to be_gem
end
end
context "#application_path" do
it "chops off the application root" do
allow(BetterErrors).to receive(:application_root).and_return("/abc/xyz")
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
expect(frame.application_path).to eq("app/controllers/crap_controller.rb")
end
end
context "#gem_path" do
it "chops of the gem path and stick (gem) there" do
allow(Gem).to receive(:path).and_return(["/abc/xyz"])
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
expect(frame.gem_path).to eq("whatever (1.2.3) lib/whatever.rb")
end
it "prioritizes gem path over application path" do
allow(BetterErrors).to receive(:application_root).and_return("/abc/xyz")
allow(Gem).to receive(:path).and_return(["/abc/xyz/vendor"])
frame = StackFrame.new("/abc/xyz/vendor/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
expect(frame.gem_path).to eq("whatever (1.2.3) lib/whatever.rb")
end
end
context "#pretty_path" do
it "returns #application_path for application paths" do
allow(BetterErrors).to receive(:application_root).and_return("/abc/xyz")
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
expect(frame.pretty_path).to eq(frame.application_path)
end
it "returns #gem_path for gem paths" do
allow(Gem).to receive(:path).and_return(["/abc/xyz"])
frame = StackFrame.new("/abc/xyz/gems/whatever-1.2.3/lib/whatever.rb", 123, "foo")
expect(frame.pretty_path).to eq(frame.gem_path)
end
end
context "#local_variable" do
it "returns exception details when #get_local_variable raises NameError" do
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
allow(frame).to receive(:get_local_variable).and_raise(NameError.new("details"))
expect(frame.local_variable("foo")).to eq("NameError: details")
end
it "returns exception details when #eval_local_variable raises NameError" do
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
allow(frame).to receive(:eval_local_variable).and_raise(NameError.new("details"))
expect(frame.local_variable("foo")).to eq("NameError: details")
end
it "raises on non-NameErrors" do
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index")
allow(frame).to receive(:get_local_variable).and_raise(ArgumentError)
expect { frame.local_variable("foo") }.to raise_error(ArgumentError)
end
end
it "special cases SyntaxErrors" do
begin
eval(%{ raise SyntaxError, "you wrote bad ruby!" }, nil, "my_file.rb", 123)
rescue SyntaxError => syntax_error
end
frames = StackFrame.from_exception(syntax_error)
expect(frames.first.filename).to eq("my_file.rb")
expect(frames.first.line).to eq(123)
end
it "doesn't blow up if no method name is given" do
error = StandardError.allocate
allow(error).to receive(:backtrace).and_return(["foo.rb:123"])
frames = StackFrame.from_exception(error)
expect(frames.first.filename).to eq("foo.rb")
expect(frames.first.line).to eq(123)
allow(error).to receive(:backtrace).and_return(["foo.rb:123: this is an error message"])
frames = StackFrame.from_exception(error)
expect(frames.first.filename).to eq("foo.rb")
expect(frames.first.line).to eq(123)
end
it "ignores a backtrace line if its format doesn't make any sense at all" do
error = StandardError.allocate
allow(error).to receive(:backtrace).and_return(["foo.rb:123:in `foo'", "C:in `find'", "bar.rb:123:in `bar'"])
frames = StackFrame.from_exception(error)
expect(frames.count).to eq(2)
end
it "doesn't blow up if a filename contains a colon" do
error = StandardError.allocate
allow(error).to receive(:backtrace).and_return(["crap:filename.rb:123"])
frames = StackFrame.from_exception(error)
expect(frames.first.filename).to eq("crap:filename.rb")
end
it "doesn't blow up with a BasicObject as frame binding" do
obj = BasicObject.new
def obj.my_binding
::Kernel.binding
end
frame = StackFrame.new("/abc/xyz/app/controllers/crap_controller.rb", 123, "index", obj.my_binding)
expect(frame.class_name).to eq('BasicObject')
end
it "sets method names properly" do
obj = "string"
def obj.my_method
begin
raise "foo"
rescue => err
err
end
end
frame = StackFrame.from_exception(obj.my_method).first
if BetterErrors.binding_of_caller_available?
expect(frame.method_name).to eq("#my_method")
expect(frame.class_name).to eq("String")
else
expect(frame.method_name).to eq("my_method")
expect(frame.class_name).to eq(nil)
end
end
if RUBY_ENGINE == "java"
it "doesn't blow up on a native Java exception" do
expect { StackFrame.from_exception(java.lang.Exception.new) }.to_not raise_error
end
end
end
end