Skip to content

Commit 2789ea5

Browse files
committed
[Kernel] Add tests for Exiting and Exception functions
1 parent 4482ed2 commit 2789ea5

File tree

3 files changed

+170
-1
lines changed

3 files changed

+170
-1
lines changed

core/kernel.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,7 @@ module Kernel : BasicObject
10041004
#
10051005
def self?.fail: () -> bot
10061006
| (string message, ?cause: Exception?) -> bot
1007-
| (_Exception exception, ?_ToS? message, ?String | Array[String] | Array[Thread::Backtrace::Location] | nil backtrace, ?cause: Exception?) -> bot
1007+
| (_Exception exception, ?string | _ToS message, ?String | Array[String] | Array[Thread::Backtrace::Location] | nil backtrace, ?cause: Exception?) -> bot
10081008
| (_Exception exception, ?cause: Exception?, **untyped) -> bot
10091009

10101010
# <!--

lib/rbs/unit_test/type_assertions.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,31 @@ def send_setup(method_type, receiver, method, args, proc)
192192
end
193193
end
194194

195+
ruby2_keywords def assert_send_type_error(method_type, error_type, receiver, method, *args, &block)
196+
send_setup(method_type, receiver, method, args, block) do |method_type, trace, result, exception|
197+
typecheck = RBS::Test::TypeCheck.new(
198+
self_class: receiver.class,
199+
builder: builder,
200+
sample_size: 100,
201+
unchecked_classes: [],
202+
instance_class: instance_class,
203+
class_class: class_class
204+
)
205+
errors = typecheck.method_call(method, method_type, trace, errors: [])
206+
207+
assert_empty errors.map {|x| RBS::Test::Errors.to_string(x) }, "Call trace does not match with given method type: #{trace.inspect}"
208+
209+
method_defs = method_defs(method)
210+
all_errors = method_defs.map {|t| typecheck.method_call(method, t.type, trace, errors: [], annotations: t.each_annotation.to_a) }
211+
assert all_errors.any? {|es| es.empty? }, "Call trace does not match one of method definitions:\n #{trace.inspect}\n #{method_defs.map(&:type).join(" | ")}"
212+
213+
# Use `instnace_of?` instead of `is_a?` as we want to check for _the exact exception class_.
214+
assert exception.instance_of? error_type
215+
216+
result
217+
end
218+
end
219+
195220
ruby2_keywords def refute_send_type(method_type, receiver, method, *args, &block)
196221
send_setup(method_type, receiver, method, args, block) do |method_type, trace, result, exception|
197222
method_type = method_type.update(

test/stdlib/Kernel_test.rb

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,150 @@ def test_String
8181
Kernel, :String, ToS.new
8282
end
8383

84+
def test_abort
85+
old_stderr = $stderr
86+
$stderr = File.open(File::NULL, 'w')
87+
88+
assert_send_type_error '() -> bot', SystemExit,
89+
Kernel, :abort
90+
91+
with_string 'oops' do |message|
92+
assert_send_type_error '(string) -> bot', SystemExit,
93+
Kernel, :abort, message
94+
end
95+
ensure
96+
$stderr.close rescue nil
97+
$stderr = old_stderr
98+
end
99+
100+
def test_exit
101+
assert_send_type_error '() -> bot', SystemExit,
102+
Kernel, :exit
103+
104+
with_int.and with_bool do |status|
105+
assert_send_type_error '(int | bool) -> bot', SystemExit,
106+
Kernel, :exit, status
107+
end
108+
end
109+
110+
def test_exit!
111+
# Sadly can't use `assert_send_type_error`, so we use exit status to check.
112+
_, status = Process.wait2(Process.spawn(RUBY_EXECUTABLE, '--disable=all', '-e', 'exit!; exit(80)'))
113+
assert_equal 1, status.exitstatus
114+
115+
_, status = Process.wait2(Process.spawn(RUBY_EXECUTABLE, '--disable=all', '-e', 'exit!(true); exit(80)'))
116+
assert_equal 0, status.exitstatus
117+
118+
_, status = Process.wait2(Process.spawn(RUBY_EXECUTABLE, '--disable=all', '-e', 'exit!(false); exit(80)'))
119+
assert_equal 1, status.exitstatus
120+
121+
_, status = Process.wait2(Process.spawn(RUBY_EXECUTABLE, '--disable=all', '-e', 'exit!(12); exit(80)'))
122+
assert_equal 12, status.exitstatus
123+
124+
_, status = Process.wait2(Process.spawn(RUBY_EXECUTABLE, '--disable=all', '-e', <<~'RUBY'))
125+
# hardcode a "blank slate" object in
126+
class ToInt < BasicObject
127+
instance_methods.each do |im|
128+
next if im == :__id__
129+
next if im == :__send__
130+
undef_method im
131+
end
132+
133+
def to_int = 12
134+
end
135+
136+
exit!(ToInt.new)
137+
exit(80)
138+
RUBY
139+
assert_equal 12, status.exitstatus
140+
end
141+
142+
def test_at_exit
143+
assert_send_type "() { () -> void } -> Proc",
144+
Kernel, :at_exit do end
145+
end
146+
147+
def test_catch
148+
assert_send_type "() { (Object) -> untyped } -> untyped",
149+
Kernel, :catch do end
150+
assert_send_type "[T] (T) { (T) -> untyped } -> untyped",
151+
Kernel, :catch, Object.new do end
152+
end
153+
154+
def test_throw
155+
# Make sure it requires an arg
156+
refute_send_type "() -> bot",
157+
Kernel, :throw
158+
159+
with_untyped do |tag|
160+
assert_send_type_error '(untyped) -> bot', UncaughtThrowError,
161+
Kernel, :throw, tag
162+
with_untyped do |obj|
163+
assert_send_type_error '(untyped, untyped) -> bot', UncaughtThrowError,
164+
Kernel, :throw, tag, obj
165+
end
166+
end
167+
end
168+
169+
TestException = Class.new(Exception)
170+
171+
def test_raise(method: :raise)
172+
assert_send_type_error '() -> bot', RuntimeError,
173+
Kernel, method
174+
175+
cause = TestException.new
176+
177+
with_string do |message|
178+
assert_send_type_error '(string) -> bot', RuntimeError,
179+
Kernel, method, message
180+
assert_send_type_error '(string, cause: nil) -> bot', RuntimeError,
181+
Kernel, method, message, cause: nil
182+
assert_send_type_error '(string, cause: Exception) -> bot', RuntimeError,
183+
Kernel, method, message, cause: cause
184+
end
185+
186+
exception = BlankSlate.new
187+
def exception.exception(mesasage = nil) = TestException.new
188+
189+
assert_send_type_error '(_Exception) -> bot', TestException,
190+
Kernel, method, exception
191+
assert_send_type_error '(_Exception, cause: nil) -> bot', TestException,
192+
Kernel, method, exception, cause: nil
193+
assert_send_type_error '(_Exception, cause: Exception) -> bot', TestException,
194+
Kernel, method, exception, cause: cause
195+
196+
with_string.and ToS.new, nil do |message|
197+
assert_send_type_error '(_Exception, string | _ToS) -> bot', TestException,
198+
Kernel, method, exception, message
199+
assert_send_type_error '(_Exception, string | _ToS, cause: nil) -> bot', TestException,
200+
Kernel, method, exception, message, cause: nil
201+
assert_send_type_error '(_Exception, string | _ToS, cause: Exception) -> bot', TestException,
202+
Kernel, method, exception, message, cause: cause
203+
204+
with "bt", caller, caller_locations, nil do |backtrace|
205+
assert_send_type_error '(_Exception, string | _ToS, String | Array[String] | Array[Thread::Backtrace::Location] | nil) -> bot', TestException,
206+
Kernel, method, exception, message, backtrace
207+
assert_send_type_error '(_Exception, string | _ToS, String | Array[String] | Array[Thread::Backtrace::Location] | nil, cause: nil) -> bot', TestException,
208+
Kernel, method, exception, message, backtrace, cause: nil
209+
assert_send_type_error '(_Exception, string | _ToS, String | Array[String] | Array[Thread::Backtrace::Location] | nil, cause: Exception) -> bot', TestException,
210+
Kernel, method, exception, message, backtrace, cause: cause
211+
end
212+
end
213+
214+
with_untyped do |value|
215+
assert_send_type_error '(_Exception, **untyped) -> bot', TestException,
216+
Kernel, method, exception, key: value
217+
assert_send_type_error '(_Exception, cause: nil, **untyped) -> bot', TestException,
218+
Kernel, method, exception, cause: nil, key: value
219+
assert_send_type_error '(_Exception, cause: Exception, **untyped) -> bot', TestException,
220+
Kernel, method, exception, cause: cause, key: value
221+
end
222+
end
223+
224+
def test_fail
225+
test_raise method: :fail
226+
end
227+
84228
def test_autoload?
85229
with_interned :TestModuleForAutoload do |interned|
86230
assert_send_type "(::interned) -> String?",

0 commit comments

Comments
 (0)