Skip to content

Commit ce80497

Browse files
committed
Fix edge cases in Kernel#raise
1 parent 51ed6aa commit ce80497

File tree

2 files changed

+116
-21
lines changed

2 files changed

+116
-21
lines changed

core/kernel/raise_spec.rb

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,53 @@
4444

4545
it "raises an ArgumentError when only cause is given" do
4646
cause = StandardError.new
47-
-> { raise(cause: cause) }.should raise_error(ArgumentError)
47+
-> { raise(cause: cause) }.should raise_error(ArgumentError, "only cause is given with no arguments")
48+
end
49+
50+
it "raises an ArgumentError when only cause is given even if it has nil value" do
51+
-> { raise(cause: nil) }.should raise_error(ArgumentError, "only cause is given with no arguments")
52+
end
53+
54+
it "raises an ArgumentError when given cause is not an instance of Exception" do
55+
-> { raise "message", cause: Object.new }.should raise_error(TypeError, "exception object expected")
56+
end
57+
58+
it "doesn't raise an ArgumentError when given cause is nil" do
59+
-> { raise "message", cause: nil }.should raise_error(RuntimeError, "message")
60+
end
61+
62+
it "allows cause equal an exception" do
63+
e = RuntimeError.new("message")
64+
-> { raise e, cause: e }.should raise_error(e)
65+
end
66+
67+
it "doesn't set given cause when it equals an exception" do
68+
e = RuntimeError.new("message")
69+
70+
begin
71+
raise e, cause: e
72+
rescue
73+
end
74+
75+
e.cause.should == nil
76+
end
77+
78+
it "raises ArgumentError when exception is part of the cause chain" do
79+
-> {
80+
begin
81+
raise "Error 1"
82+
rescue => e1
83+
begin
84+
raise "Error 2"
85+
rescue => e2
86+
begin
87+
raise "Error 3"
88+
rescue => e3
89+
raise e1, cause: e3
90+
end
91+
end
92+
end
93+
}.should raise_error(ArgumentError, "circular causes")
4894
end
4995

5096
it "re-raises a rescued exception" do
@@ -106,6 +152,57 @@
106152
e.cause.should == e4
107153
end
108154
end
155+
156+
it "re-raises a previously rescued exception without overwriting the cause when it's explicitly specified with :cause option and has nil value" do
157+
begin
158+
begin
159+
begin
160+
begin
161+
raise "Error 1"
162+
rescue => e1
163+
raise "Error 2"
164+
end
165+
rescue => e2
166+
raise "Error 3"
167+
end
168+
rescue
169+
e2.cause.should == e1
170+
raise e2, cause: nil
171+
end
172+
rescue => e
173+
e.cause.should == e1
174+
end
175+
end
176+
177+
it "re-raises a previously rescued exception without setting a cause implicitly" do
178+
begin
179+
begin
180+
raise "Error 1"
181+
rescue => e1
182+
raise
183+
end
184+
rescue => e
185+
e.should == e1
186+
e.cause.should == nil
187+
end
188+
end
189+
190+
it "re-raises a previously rescued exception that has a cause without setting a cause implicitly" do
191+
begin
192+
begin
193+
raise "Error 1"
194+
rescue => e1
195+
begin
196+
raise "Error 2"
197+
rescue => e2
198+
raise
199+
end
200+
end
201+
rescue => e
202+
e.should == e2
203+
e.cause.should == e1
204+
end
205+
end
109206
end
110207

111208
describe "Kernel#raise" do

shared/kernel/raise.rb

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,6 @@ def initialize(data)
4949
end
5050
end
5151

52-
it "does not allow message and extra keyword arguments" do
53-
data_error = Class.new(StandardError) do
54-
attr_reader :data
55-
def initialize(data)
56-
@data = data
57-
end
58-
end
59-
60-
-> { @object.raise(data_error, {a: 1}, b: 2) }.should raise_error(StandardError) do |e|
61-
[TypeError, ArgumentError].should.include?(e.class)
62-
end
63-
64-
-> { @object.raise(data_error, {a: 1}, [], b: 2) }.should raise_error(ArgumentError)
65-
end
66-
6752
it "raises RuntimeError if no exception class is given" do
6853
-> { @object.raise }.should raise_error(RuntimeError, "")
6954
end
@@ -74,7 +59,7 @@ def initialize(data)
7459
end
7560

7661
it "raises a RuntimeError if string given" do
77-
-> { @object.raise("a bad thing") }.should raise_error(RuntimeError)
62+
-> { @object.raise("a bad thing") }.should raise_error(RuntimeError, "a bad thing")
7863
end
7964

8065
it "passes no arguments to the constructor when given only an exception class" do
@@ -86,19 +71,32 @@ def initialize
8671
end
8772

8873
it "raises a TypeError when passed a non-Exception object" do
89-
-> { @object.raise(Object.new) }.should raise_error(TypeError)
74+
-> { @object.raise(Object.new) }.should raise_error(TypeError, "exception class/object expected")
75+
-> { @object.raise(Object.new, "message") }.should raise_error(TypeError, "exception class/object expected")
76+
-> { @object.raise(Object.new, "message", []) }.should raise_error(TypeError, "exception class/object expected")
9077
end
9178

9279
it "raises a TypeError when passed true" do
93-
-> { @object.raise(true) }.should raise_error(TypeError)
80+
-> { @object.raise(true) }.should raise_error(TypeError, "exception class/object expected")
9481
end
9582

9683
it "raises a TypeError when passed false" do
97-
-> { @object.raise(false) }.should raise_error(TypeError)
84+
-> { @object.raise(false) }.should raise_error(TypeError, "exception class/object expected")
9885
end
9986

10087
it "raises a TypeError when passed nil" do
101-
-> { @object.raise(nil) }.should raise_error(TypeError)
88+
-> { @object.raise(nil) }.should raise_error(TypeError, "exception class/object expected")
89+
end
90+
91+
it "raises TypeError when passed a non-Exception object but it responds to #exception method that doesn't return an instance of Exception class" do
92+
e = Object.new
93+
def e.exception
94+
Array
95+
end
96+
97+
-> {
98+
@object.raise e
99+
}.should raise_error(TypeError, "exception object expected")
102100
end
103101

104102
it "re-raises a previously rescued exception without overwriting the backtrace" do

0 commit comments

Comments
 (0)