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 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
|
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
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
guard -> { Kernel.instance_method(:tap).source_location } do
it "skips <internal: core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
file.should.start_with?('<internal:')
file = fixture(__FILE__ , "warn_core_method.rb")
n = 9
ruby_exe(file, options: "--disable-gems", args: "2>&1").lines.should == [
"#{file}:#{n+0}: warning: use X instead\n",
"#{file}:#{n+1}: warning: use X instead\n",
"#{file}:#{n+2}: warning: use X instead\n",
"#{file}:#{n+4}: warning: use X instead\n",
]
end
end
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
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
it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do
verbose = $VERBOSE
$VERBOSE = false
class << Warning
alias_method :_warn, :warn
def warn(message)
ScratchPad.record(message)
end
end
begin
ScratchPad.clear
Kernel.warn("Chunky bacon!")
ScratchPad.recorded.should == "Chunky bacon!\n"
Kernel.warn("Deprecated bacon!", category: :deprecated)
ScratchPad.recorded.should == "Deprecated bacon!\n"
ensure
class << Warning
remove_method :warn
alias_method :warn, :_warn
remove_method :_warn
end
$VERBOSE = verbose
end
end
it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do
Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
verbose = $VERBOSE
$VERBOSE = false
begin
Kernel.warn("Chunky bacon!")
ensure
$VERBOSE = verbose
end
end
it "calls Warning.warn with given category keyword converted to a symbol" do
Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
verbose = $VERBOSE
$VERBOSE = false
begin
Kernel.warn("Chunky bacon!", category: 'deprecated')
ensure
$VERBOSE = verbose
end
end
it "does not call Warning.warn if self is the Warning module" do
# RubyGems redefines Kernel#warn so we need to use a subprocess and disable RubyGems here
code = <<-RUBY
def Warning.warn(*args, **kwargs)
raise 'should not be called'
end
Kernel.instance_method(:warn).bind(Warning).call('Kernel#warn spec edge case')
RUBY
out = ruby_exe(code, args: "2>&1", options: "--disable-gems")
out.should == "Kernel#warn spec edge case\n"
$?.should.success?
end
it "avoids recursion if Warning#warn is redefined and calls super" do
# This works because of the spec above, which is the workaround for it.
# Note that redefining Warning#warn is a mistake which would naturally end in infinite recursion,
# Warning.extend Module.new { def warn } should be used instead.
# RubyGems redefines Kernel#warn so we need to use a subprocess and disable RubyGems here
code = <<-RUBY
module Warning
def warn(*args, **kwargs)
super
end
end
warn "avoid infinite recursion"
RUBY
out = ruby_exe(code, args: "2>&1", options: "--disable-gems")
out.should == "avoid infinite recursion\n"
$?.should.success?
end
end
|