1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/spec/ruby/core/kernel/warn_spec.rb
Jeremy Evans 346301e232 Add rb_category_warn{,ing} for warning messages with categories
This adds the following C-API functions that can be used to emit
warnings with categories included:

```c
void rb_category_warn(const char *, const char*, ...)
void rb_category_warning(const char*, const char*, ...)
```

Internally in error.c, there is an rb_warn_category function
that will call Warning.warn with the string and the category
keyword if it doesn't have an arity of 1, and will call
Warning.warn with just the string if it has an arity of 1.
This refactors the rb_warn_deprecated{,_to_remove} functions
to use rb_warn_category.

This makes Kernel#warn accept a category keyword and pass it
to Warning.warn, so that Ruby methods can more easily emit
warnings with categories.  rb_warn_category makes sure that
the passed category is a already defined category symbol
before calling Warning.warn.

The only currently defined warning category is :deprecated,
since that is what is already used.  More categories can be
added in later commits.
2020-09-28 08:38:06 -07:00

200 lines
6.5 KiB
Ruby

require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#warn" do
before :each do
@before_verbose = $VERBOSE
@before_separator = $/
end
after :each do
$VERBOSE = nil
$/ = @before_separator
$VERBOSE = @before_verbose
end
it "is a private method" do
Kernel.should have_private_instance_method(:warn)
end
it "accepts multiple arguments" do
Kernel.method(:warn).arity.should < 0
end
it "does not append line-end if last character is line-end" do
-> {
$VERBOSE = true
warn("this is some simple text with line-end\n")
}.should output(nil, "this is some simple text with line-end\n")
end
it "calls #write on $stderr if $VERBOSE is true" do
-> {
$VERBOSE = true
warn("this is some simple text")
}.should output(nil, "this is some simple text\n")
end
it "calls #write on $stderr if $VERBOSE is false" do
-> {
$VERBOSE = false
warn("this is some simple text")
}.should output(nil, "this is some simple text\n")
end
it "does not call #write on $stderr if $VERBOSE is nil" do
-> {
$VERBOSE = nil
warn("this is some simple text")
}.should output(nil, "")
end
it "writes each argument on a line when passed multiple arguments" do
-> {
$VERBOSE = true
warn("line 1", "line 2")
}.should output(nil, "line 1\nline 2\n")
end
it "writes each array element on a line when passes an array" do
-> {
$VERBOSE = true
warn(["line 1", "line 2"])
}.should output(nil, "line 1\nline 2\n")
end
it "does not write strings when passed no arguments" do
-> {
$VERBOSE = true
warn
}.should output("", "")
end
it "writes the default record separator and NOT $/ to $stderr after the warning message" do
-> {
$VERBOSE = true
$/ = 'rs'
warn("")
}.should output(nil, /\n/)
end
it "writes to_s representation if passed a non-string" do
obj = mock("obj")
obj.should_receive(:to_s).and_return("to_s called")
-> {
$VERBOSE = true
warn(obj)
}.should output(nil, "to_s called\n")
end
describe ":uplevel keyword argument" do
before :each do
$VERBOSE = true
end
it "prepends a message with specified line from the backtrace" do
w = KernelSpecs::WarnInNestedCall.new
-> { w.f4("foo", 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: foo|)
-> { w.f4("foo", 1) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f1_call_lineno}: warning: foo|)
-> { w.f4("foo", 2) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f2_call_lineno}: warning: foo|)
-> { w.f4("foo", 3) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f3_call_lineno}: warning: foo|)
end
# Test both explicitly without and with RubyGems as RubyGems overrides Kernel#warn
it "shows the caller of #require and not #require itself without RubyGems" do
file = fixture(__FILE__ , "warn_require_caller.rb")
ruby_exe(file, options: "--disable-gems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
end
ruby_version_is "2.6" do
it "shows the caller of #require and not #require itself with RubyGems loaded" do
file = fixture(__FILE__ , "warn_require_caller.rb")
ruby_exe(file, options: "-rrubygems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
end
end
ruby_version_is "3.0" do
it "accepts :category keyword with a symbol" do
-> {
$VERBOSE = true
warn("message", category: :deprecated)
}.should output(nil, "message\n")
end
it "accepts :category keyword with nil" do
-> {
$VERBOSE = true
warn("message", category: nil)
}.should output(nil, "message\n")
end
it "accepts :category keyword with object convertible to symbol" do
o = Object.new
def o.to_sym; :deprecated; end
-> {
$VERBOSE = true
warn("message", category: o)
}.should output(nil, "message\n")
end
it "raises if :category keyword is not nil and not convertible to symbol" do
-> {
$VERBOSE = true
warn("message", category: Object.new)
}.should raise_error(TypeError)
end
end
it "converts first arg using to_s" do
w = KernelSpecs::WarnInNestedCall.new
-> { w.f4(false, 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: false|)
-> { w.f4(nil, 1) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f1_call_lineno}: warning: |)
obj = mock("obj")
obj.should_receive(:to_s).and_return("to_s called")
-> { w.f4(obj, 2) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f2_call_lineno}: warning: to_s called|)
end
it "does not prepend caller information if the uplevel argument is too large" do
w = KernelSpecs::WarnInNestedCall.new
-> { w.f4("foo", 100) }.should output(nil, "warning: foo\n")
end
it "prepends even if a message is empty or nil" do
w = KernelSpecs::WarnInNestedCall.new
-> { w.f4("", 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: \n$|)
-> { w.f4(nil, 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: \n$|)
end
it "converts value to Integer" do
w = KernelSpecs::WarnInNestedCall.new
-> { w.f4(0.1) }.should output(nil, %r|classes.rb:#{w.warn_call_lineno}:|)
-> { w.f4(Rational(1, 2)) }.should output(nil, %r|classes.rb:#{w.warn_call_lineno}:|)
end
it "raises ArgumentError if passed negative value" do
-> { warn "", uplevel: -2 }.should raise_error(ArgumentError)
-> { warn "", uplevel: -100 }.should raise_error(ArgumentError)
end
it "raises ArgumentError if passed -1" do
-> { warn "", uplevel: -1 }.should raise_error(ArgumentError)
end
it "raises TypeError if passed not Integer" do
-> { warn "", uplevel: "" }.should raise_error(TypeError)
-> { warn "", uplevel: [] }.should raise_error(TypeError)
-> { warn "", uplevel: {} }.should raise_error(TypeError)
-> { warn "", uplevel: Object.new }.should raise_error(TypeError)
end
end
it "treats empty hash as no keyword argument" do
h = {}
-> { warn(**h) }.should_not complain(verbose: true)
-> { warn('foo', **h) }.should complain("foo\n")
end
end