mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[WIP] add error_squiggle gem
``` $ ./local/bin/ruby -e '1.time {}' -e:1:in `<main>': undefined method `time' for 1:Integer (NoMethodError) 1.time {} ^^^^^ Did you mean? times ``` https://bugs.ruby-lang.org/issues/17930
This commit is contained in:
parent
03dc664493
commit
e946049665
Notes:
git
2021-06-29 23:46:18 +09:00
14 changed files with 1503 additions and 8 deletions
|
@ -4,6 +4,12 @@ rescue LoadError
|
|||
warn "`RubyGems' were not loaded."
|
||||
end if defined?(Gem)
|
||||
|
||||
begin
|
||||
require 'error_squiggle'
|
||||
rescue LoadError
|
||||
warn "`error_squiggle' was not loaded."
|
||||
end if defined?(ErrorSquiggle)
|
||||
|
||||
begin
|
||||
require 'did_you_mean'
|
||||
rescue LoadError
|
||||
|
|
2
lib/error_squiggle.rb
Normal file
2
lib/error_squiggle.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
require_relative "error_squiggle/base"
|
||||
require_relative "error_squiggle/core_ext"
|
446
lib/error_squiggle/base.rb
Normal file
446
lib/error_squiggle/base.rb
Normal file
|
@ -0,0 +1,446 @@
|
|||
require_relative "version"
|
||||
|
||||
module ErrorSquiggle
|
||||
# Identify the code fragment that seems associated with a given error
|
||||
#
|
||||
# Arguments:
|
||||
# node: RubyVM::AbstractSyntaxTree::Node
|
||||
# point: :name | :args
|
||||
# name: The name associated with the NameError/NoMethodError
|
||||
# fetch: A block to fetch a specified code line (or lines)
|
||||
#
|
||||
# Returns:
|
||||
# {
|
||||
# first_lineno: Integer,
|
||||
# first_column: Integer,
|
||||
# last_lineno: Integer,
|
||||
# last_column: Integer,
|
||||
# line: String,
|
||||
# } | nil
|
||||
def self.spot(...)
|
||||
Spotter.new(...).spot
|
||||
end
|
||||
|
||||
class Spotter
|
||||
def initialize(node, point, name: nil, &fetch)
|
||||
@node = node
|
||||
@point = point
|
||||
@name = name
|
||||
|
||||
# Not-implemented-yet options
|
||||
@arg = nil # Specify the index or keyword at which argument caused the TypeError/ArgumentError
|
||||
@multiline = false # Allow multiline spot
|
||||
|
||||
@fetch = fetch
|
||||
end
|
||||
|
||||
def spot
|
||||
return nil unless @node
|
||||
|
||||
case @node.type
|
||||
|
||||
when :CALL, :QCALL
|
||||
case @point
|
||||
when :name
|
||||
spot_call_for_name
|
||||
when :args
|
||||
spot_call_for_args
|
||||
end
|
||||
|
||||
when :ATTRASGN
|
||||
case @point
|
||||
when :name
|
||||
spot_attrasgn_for_name
|
||||
when :args
|
||||
spot_attrasgn_for_args
|
||||
end
|
||||
|
||||
when :OPCALL
|
||||
case @point
|
||||
when :name
|
||||
spot_opcall_for_name
|
||||
when :args
|
||||
spot_opcall_for_args
|
||||
end
|
||||
|
||||
when :FCALL
|
||||
case @point
|
||||
when :name
|
||||
spot_fcall_for_name
|
||||
when :args
|
||||
spot_fcall_for_args
|
||||
end
|
||||
|
||||
when :VCALL
|
||||
spot_vcall
|
||||
|
||||
when :OP_ASGN1
|
||||
case @point
|
||||
when :name
|
||||
spot_op_asgn1_for_name
|
||||
when :args
|
||||
spot_op_asgn1_for_args
|
||||
end
|
||||
|
||||
when :OP_ASGN2
|
||||
case @point
|
||||
when :name
|
||||
spot_op_asgn2_for_name
|
||||
when :args
|
||||
spot_op_asgn2_for_args
|
||||
end
|
||||
|
||||
when :CONST
|
||||
spot_vcall
|
||||
|
||||
when :COLON2
|
||||
spot_colon2
|
||||
|
||||
when :COLON3
|
||||
spot_vcall
|
||||
|
||||
when :OP_CDECL
|
||||
spot_op_cdecl
|
||||
end
|
||||
|
||||
if @line && @beg_column && @end_column && @beg_column < @end_column
|
||||
return {
|
||||
first_lineno: @beg_lineno,
|
||||
first_column: @beg_column,
|
||||
last_lineno: @end_lineno,
|
||||
last_column: @end_column,
|
||||
line: @line,
|
||||
}
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Example:
|
||||
# x.foo
|
||||
# ^^^^
|
||||
# x.foo(42)
|
||||
# ^^^^
|
||||
# x&.foo
|
||||
# ^^^^^
|
||||
# x[42]
|
||||
# ^^^^
|
||||
# x += 1
|
||||
# ^
|
||||
def spot_call_for_name
|
||||
nd_recv, mid, nd_args = @node.children
|
||||
lineno = nd_recv.last_lineno
|
||||
lines = @fetch[lineno, @node.last_lineno]
|
||||
if mid == :[] && lines.match(/\G\s*(\[(?:\s*\])?)/, nd_recv.last_column)
|
||||
@beg_column = $~.begin(1)
|
||||
@line = lines[/.*\n/]
|
||||
@beg_lineno = @end_lineno = lineno
|
||||
if nd_args
|
||||
if nd_recv.last_lineno == nd_args.last_lineno && @line.match(/\s*\]/, nd_args.last_column)
|
||||
@end_column = $~.end(0)
|
||||
end
|
||||
else
|
||||
if lines.match(/\G\s*?\[\s*\]/, nd_recv.last_column)
|
||||
@end_column = $~.end(0)
|
||||
end
|
||||
end
|
||||
elsif lines.match(/\G\s*?(\&?\.)(\s*?)(#{ Regexp.quote(mid) }).*\n/, nd_recv.last_column)
|
||||
lines = $` + $&
|
||||
@beg_column = $~.begin($2.include?("\n") ? 3 : 1)
|
||||
@end_column = $~.end(3)
|
||||
if i = lines[..@beg_column].rindex("\n")
|
||||
@beg_lineno = @end_lineno = lineno + lines[..@beg_column].count("\n")
|
||||
@line = lines[i + 1..]
|
||||
@beg_column -= i + 1
|
||||
@end_column -= i + 1
|
||||
else
|
||||
@line = lines
|
||||
@beg_lineno = @end_lineno = lineno
|
||||
end
|
||||
elsif mid.to_s =~ /\A\W+\z/ && lines.match(/\G\s*(#{ Regexp.quote(mid) })=.*\n/, nd_recv.last_column)
|
||||
@line = $` + $&
|
||||
@beg_column = $~.begin(1)
|
||||
@end_column = $~.end(1)
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x.foo(42)
|
||||
# ^^
|
||||
# x[42]
|
||||
# ^^
|
||||
# x += 1
|
||||
# ^
|
||||
def spot_call_for_args
|
||||
_nd_recv, _mid, nd_args = @node.children
|
||||
if nd_args && nd_args.first_lineno == nd_args.last_lineno
|
||||
fetch_line(nd_args.first_lineno)
|
||||
@beg_column = nd_args.first_column
|
||||
@end_column = nd_args.last_column
|
||||
end
|
||||
# TODO: support @arg
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x.foo = 1
|
||||
# ^^^^^^
|
||||
# x[42] = 1
|
||||
# ^^^^^^
|
||||
def spot_attrasgn_for_name
|
||||
nd_recv, mid, nd_args = @node.children
|
||||
*nd_args, _nd_last_arg, _nil = nd_args.children
|
||||
fetch_line(nd_recv.last_lineno)
|
||||
if mid == :[]= && @line.match(/\G\s*(\[)/, nd_recv.last_column)
|
||||
@beg_column = $~.begin(1)
|
||||
args_last_column = $~.end(0)
|
||||
if nd_args.last && nd_recv.last_lineno == nd_args.last.last_lineno
|
||||
args_last_column = nd_args.last.last_column
|
||||
end
|
||||
if @line.match(/\s*\]\s*=/, args_last_column)
|
||||
@end_column = $~.end(0)
|
||||
end
|
||||
elsif @line.match(/\G\s*(\.\s*#{ Regexp.quote(mid.to_s.sub(/=\z/, "")) }\s*=)/, nd_recv.last_column)
|
||||
@beg_column = $~.begin(1)
|
||||
@end_column = $~.end(1)
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x.foo = 1
|
||||
# ^
|
||||
# x[42] = 1
|
||||
# ^^^^^^^
|
||||
# x[] = 1
|
||||
# ^^^^^
|
||||
def spot_attrasgn_for_args
|
||||
nd_recv, mid, nd_args = @node.children
|
||||
fetch_line(nd_recv.last_lineno)
|
||||
if mid == :[]= && @line.match(/\G\s*\[/, nd_recv.last_column)
|
||||
@beg_column = $~.end(0)
|
||||
if nd_recv.last_lineno == nd_args.last_lineno
|
||||
@end_column = nd_args.last_column
|
||||
end
|
||||
elsif nd_args && nd_args.first_lineno == nd_args.last_lineno
|
||||
@beg_column = nd_args.first_column
|
||||
@end_column = nd_args.last_column
|
||||
end
|
||||
# TODO: support @arg
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x + 1
|
||||
# ^
|
||||
# +x
|
||||
# ^
|
||||
def spot_opcall_for_name
|
||||
nd_recv, op, nd_arg = @node.children
|
||||
fetch_line(nd_recv.last_lineno)
|
||||
if nd_arg
|
||||
# binary operator
|
||||
if @line.match(/\G\s*(#{ Regexp.quote(op) })/, nd_recv.last_column)
|
||||
@beg_column = $~.begin(1)
|
||||
@end_column = $~.end(1)
|
||||
end
|
||||
else
|
||||
# unary operator
|
||||
if @line[...nd_recv.first_column].match(/(#{ Regexp.quote(op.to_s.sub(/@\z/, "")) })\s*\(?\s*\z/)
|
||||
@beg_column = $~.begin(1)
|
||||
@end_column = $~.end(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x + 1
|
||||
# ^
|
||||
def spot_opcall_for_args
|
||||
_nd_recv, _op, nd_arg = @node.children
|
||||
if nd_arg && nd_arg.first_lineno == nd_arg.last_lineno
|
||||
# binary operator
|
||||
fetch_line(nd_arg.first_lineno)
|
||||
@beg_column = nd_arg.first_column
|
||||
@end_column = nd_arg.last_column
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# foo(42)
|
||||
# ^^^
|
||||
# foo 42
|
||||
# ^^^
|
||||
def spot_fcall_for_name
|
||||
mid, _nd_args = @node.children
|
||||
fetch_line(@node.first_lineno)
|
||||
if @line.match(/(#{ Regexp.quote(mid) })/, @node.first_column)
|
||||
@beg_column = $~.begin(1)
|
||||
@end_column = $~.end(1)
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# foo(42)
|
||||
# ^^
|
||||
# foo 42
|
||||
# ^^
|
||||
def spot_fcall_for_args
|
||||
_mid, nd_args = @node.children
|
||||
if nd_args && nd_args.first_lineno == nd_args.last_lineno
|
||||
# binary operator
|
||||
fetch_line(nd_args.first_lineno)
|
||||
@beg_column = nd_args.first_column
|
||||
@end_column = nd_args.last_column
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# foo
|
||||
# ^^^
|
||||
def spot_vcall
|
||||
if @node.first_lineno == @node.last_lineno
|
||||
fetch_line(@node.last_lineno)
|
||||
@beg_column = @node.first_column
|
||||
@end_column = @node.last_column
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x[1] += 42
|
||||
# ^^^ (for [])
|
||||
# x[1] += 42
|
||||
# ^ (for +)
|
||||
# x[1] += 42
|
||||
# ^^^^^^ (for []=)
|
||||
def spot_op_asgn1_for_name
|
||||
nd_recv, op, nd_args, _nd_rhs = @node.children
|
||||
fetch_line(nd_recv.last_lineno)
|
||||
if @line.match(/\G\s*(\[)/, nd_recv.last_column)
|
||||
bracket_beg_column = $~.begin(1)
|
||||
args_last_column = $~.end(0)
|
||||
if nd_args && nd_recv.last_lineno == nd_args.last_lineno
|
||||
args_last_column = nd_args.last_column
|
||||
end
|
||||
if @line.match(/\s*\](\s*)(#{ Regexp.quote(op) })=()/, args_last_column)
|
||||
case @name
|
||||
when :[], :[]=
|
||||
@beg_column = bracket_beg_column
|
||||
@end_column = $~.begin(@name == :[] ? 1 : 3)
|
||||
when op
|
||||
@beg_column = $~.begin(2)
|
||||
@end_column = $~.end(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x[1] += 42
|
||||
# ^^^^^^^^
|
||||
def spot_op_asgn1_for_args
|
||||
nd_recv, mid, nd_args, nd_rhs = @node.children
|
||||
fetch_line(nd_recv.last_lineno)
|
||||
if mid == :[]= && @line.match(/\G\s*\[/, nd_recv.last_column)
|
||||
@beg_column = $~.end(0)
|
||||
if nd_recv.last_lineno == nd_rhs.last_lineno
|
||||
@end_column = nd_rhs.last_column
|
||||
end
|
||||
elsif nd_args && nd_args.first_lineno == nd_rhs.last_lineno
|
||||
@beg_column = nd_args.first_column
|
||||
@end_column = nd_rhs.last_column
|
||||
end
|
||||
# TODO: support @arg
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x.foo += 42
|
||||
# ^^^ (for foo)
|
||||
# x.foo += 42
|
||||
# ^ (for +)
|
||||
# x.foo += 42
|
||||
# ^^^^^^^ (for foo=)
|
||||
def spot_op_asgn2_for_name
|
||||
nd_recv, _qcall, attr, op, _nd_rhs = @node.children
|
||||
fetch_line(nd_recv.last_lineno)
|
||||
if @line.match(/\G\s*(\.)\s*#{ Regexp.quote(attr) }()\s*(#{ Regexp.quote(op) })(=)/, nd_recv.last_column)
|
||||
case @name
|
||||
when attr
|
||||
@beg_column = $~.begin(1)
|
||||
@end_column = $~.begin(2)
|
||||
when op
|
||||
@beg_column = $~.begin(3)
|
||||
@end_column = $~.end(3)
|
||||
when :"#{ attr }="
|
||||
@beg_column = $~.begin(1)
|
||||
@end_column = $~.end(4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# x.foo += 42
|
||||
# ^^
|
||||
def spot_op_asgn2_for_args
|
||||
_nd_recv, _qcall, _attr, _op, nd_rhs = @node.children
|
||||
if nd_rhs.first_lineno == nd_rhs.last_lineno
|
||||
fetch_line(nd_rhs.first_lineno)
|
||||
@beg_column = nd_rhs.first_column
|
||||
@end_column = nd_rhs.last_column
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# Foo::Bar
|
||||
# ^^^^^
|
||||
def spot_colon2
|
||||
nd_parent, const = @node.children
|
||||
if nd_parent.last_lineno == @node.last_lineno
|
||||
fetch_line(nd_parent.last_lineno)
|
||||
@beg_column = nd_parent.last_column
|
||||
@end_column = @node.last_column
|
||||
else
|
||||
@line = @fetch[@node.last_lineno]
|
||||
if @line[...@node.last_column].match(/#{ Regexp.quote(const) }\z/)
|
||||
@beg_column = $~.begin(0)
|
||||
@end_column = $~.end(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Example:
|
||||
# Foo::Bar += 1
|
||||
# ^^^^^^^^
|
||||
def spot_op_cdecl
|
||||
nd_lhs, op, _nd_rhs = @node.children
|
||||
*nd_parent_lhs, _const = nd_lhs.children
|
||||
if @name == op
|
||||
@line = @fetch[nd_lhs.last_lineno]
|
||||
if @line.match(/\G\s*(#{ Regexp.quote(op) })=/, nd_lhs.last_column)
|
||||
@beg_column = $~.begin(1)
|
||||
@end_column = $~.end(1)
|
||||
end
|
||||
else
|
||||
# constant access error
|
||||
@end_column = nd_lhs.last_column
|
||||
if nd_parent_lhs.empty? # example: ::C += 1
|
||||
if nd_lhs.first_lineno == nd_lhs.last_lineno
|
||||
@line = @fetch[nd_lhs.last_lineno]
|
||||
@beg_column = nd_lhs.first_column
|
||||
end
|
||||
else # example: Foo::Bar::C += 1
|
||||
if nd_parent_lhs.last.last_lineno == nd_lhs.last_lineno
|
||||
@line = @fetch[nd_lhs.last_lineno]
|
||||
@beg_column = nd_parent_lhs.last.last_column
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_line(lineno)
|
||||
@beg_lineno = @end_lineno = lineno
|
||||
@line = @fetch[lineno]
|
||||
end
|
||||
end
|
||||
|
||||
private_constant :Spotter
|
||||
end
|
48
lib/error_squiggle/core_ext.rb
Normal file
48
lib/error_squiggle/core_ext.rb
Normal file
|
@ -0,0 +1,48 @@
|
|||
module ErrorSquiggle
|
||||
module CoreExt
|
||||
SKIP_TO_S_FOR_SUPER_LOOKUP = true
|
||||
private_constant :SKIP_TO_S_FOR_SUPER_LOOKUP
|
||||
|
||||
def to_s
|
||||
msg = super.dup
|
||||
|
||||
locs = backtrace_locations
|
||||
return msg unless locs
|
||||
|
||||
loc = locs.first
|
||||
begin
|
||||
node = RubyVM::AbstractSyntaxTree.of(loc, save_script_lines: true)
|
||||
opts = {}
|
||||
|
||||
case self
|
||||
when NoMethodError, NameError
|
||||
point = :name
|
||||
opts[:name] = name
|
||||
when TypeError, ArgumentError
|
||||
point = :args
|
||||
end
|
||||
|
||||
spot = ErrorSquiggle.spot(node, point, **opts) do |lineno, last_lineno|
|
||||
last_lineno ||= lineno
|
||||
node.script_lines[lineno - 1 .. last_lineno - 1].join("")
|
||||
end
|
||||
|
||||
rescue Errno::ENOENT
|
||||
end
|
||||
|
||||
if spot
|
||||
marker = " " * spot[:first_column] + "^" * (spot[:last_column] - spot[:first_column])
|
||||
points = "\n\n#{ spot[:line] }#{ marker }"
|
||||
msg << points if !msg.include?(points)
|
||||
end
|
||||
|
||||
msg
|
||||
end
|
||||
end
|
||||
|
||||
NameError.prepend(CoreExt)
|
||||
|
||||
# temporarily disabled
|
||||
#TypeError.prepend(CoreExt)
|
||||
#ArgumentError.prepend(CoreExt)
|
||||
end
|
3
lib/error_squiggle/version.rb
Normal file
3
lib/error_squiggle/version.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
module ErrorSquiggle
|
||||
VERSION = "0.1.0"
|
||||
end
|
6
ruby.c
6
ruby.c
|
@ -94,6 +94,8 @@ void rb_warning_category_update(unsigned int mask, unsigned int bits);
|
|||
#define EACH_FEATURES(X, SEP) \
|
||||
X(gems) \
|
||||
SEP \
|
||||
X(error_squiggle) \
|
||||
SEP \
|
||||
X(did_you_mean) \
|
||||
SEP \
|
||||
X(rubyopt) \
|
||||
|
@ -320,6 +322,7 @@ usage(const char *name, int help, int highlight, int columns)
|
|||
};
|
||||
static const struct message features[] = {
|
||||
M("gems", "", "rubygems (only for debugging, default: "DEFAULT_RUBYGEMS_ENABLED")"),
|
||||
M("error_squiggle", "", "error_squiggle (default: "DEFAULT_RUBYGEMS_ENABLED")"),
|
||||
M("did_you_mean", "", "did_you_mean (default: "DEFAULT_RUBYGEMS_ENABLED")"),
|
||||
M("rubyopt", "", "RUBYOPT environment variable (default: enabled)"),
|
||||
M("frozen-string-literal", "", "freeze all string literals (default: disabled)"),
|
||||
|
@ -1508,6 +1511,9 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
|
|||
|
||||
if (opt->features.set & FEATURE_BIT(gems)) {
|
||||
rb_define_module("Gem");
|
||||
if (opt->features.set & FEATURE_BIT(error_squiggle)) {
|
||||
rb_define_module("ErrorSquiggle");
|
||||
}
|
||||
if (opt->features.set & FEATURE_BIT(did_you_mean)) {
|
||||
rb_define_module("DidYouMean");
|
||||
}
|
||||
|
|
|
@ -110,14 +110,14 @@ describe "NoMethodError#message" do
|
|||
begin
|
||||
klass.foo
|
||||
rescue NoMethodError => error
|
||||
error.message.lines.first.should == "undefined method `foo' for MyClass:Class"
|
||||
error.message.lines.first.chomp.should == "undefined method `foo' for MyClass:Class"
|
||||
end
|
||||
|
||||
mod = Module.new { def self.name; "MyModule"; end }
|
||||
begin
|
||||
mod.foo
|
||||
rescue NoMethodError => error
|
||||
error.message.lines.first.should == "undefined method `foo' for MyModule:Module"
|
||||
error.message.lines.first.chomp.should == "undefined method `foo' for MyModule:Module"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
984
test/error_squiggle/test_error_squiggle.rb
Normal file
984
test/error_squiggle/test_error_squiggle.rb
Normal file
|
@ -0,0 +1,984 @@
|
|||
require "test/unit"
|
||||
|
||||
require "error_squiggle"
|
||||
|
||||
class ErrorSquiggleTest < Test::Unit::TestCase
|
||||
class DummyFormatter
|
||||
def message_for(corrections)
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
if defined?(DidYouMean)
|
||||
@did_you_mean_old_formatter = DidYouMean.formatter
|
||||
DidYouMean.formatter = DummyFormatter
|
||||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
if defined?(DidYouMean)
|
||||
DidYouMean.formatter = @did_you_mean_old_formatter
|
||||
end
|
||||
end
|
||||
|
||||
def assert_error_message(klass, expected_msg, &blk)
|
||||
err = assert_raise(klass, &blk)
|
||||
assert_equal(expected_msg.chomp, err.message)
|
||||
end
|
||||
|
||||
def test_CALL_noarg_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
nil.foo + 1
|
||||
^^^^
|
||||
END
|
||||
|
||||
nil.foo + 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_noarg_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
.foo + 1
|
||||
^^^^
|
||||
END
|
||||
|
||||
nil
|
||||
.foo + 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_noarg_3
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
foo + 1
|
||||
^^^
|
||||
END
|
||||
|
||||
nil.
|
||||
foo + 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_arg_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
nil.foo (42)
|
||||
^^^^
|
||||
END
|
||||
|
||||
nil.foo (42)
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_arg_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
.foo (
|
||||
^^^^
|
||||
END
|
||||
|
||||
nil
|
||||
.foo (
|
||||
42
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_arg_3
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
foo (
|
||||
^^^
|
||||
END
|
||||
|
||||
nil.
|
||||
foo (
|
||||
42
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_arg_4
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
nil.foo(42)
|
||||
^^^^
|
||||
END
|
||||
|
||||
nil.foo(42)
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_arg_5
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
.foo(
|
||||
^^^^
|
||||
END
|
||||
|
||||
nil
|
||||
.foo(
|
||||
42
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_arg_6
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
foo(
|
||||
^^^
|
||||
END
|
||||
|
||||
nil.
|
||||
foo(
|
||||
42
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_QCALL_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for 1:Integer
|
||||
|
||||
1&.foo
|
||||
^^^^^
|
||||
END
|
||||
|
||||
1&.foo
|
||||
end
|
||||
end
|
||||
|
||||
def test_QCALL_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for 1:Integer
|
||||
|
||||
1&.foo(42)
|
||||
^^^^^
|
||||
END
|
||||
|
||||
1&.foo(42)
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_aref_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]' for nil:NilClass
|
||||
|
||||
nil [ ]
|
||||
^^^
|
||||
END
|
||||
|
||||
nil [ ]
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_aref_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]' for nil:NilClass
|
||||
|
||||
nil [0]
|
||||
^^^
|
||||
END
|
||||
|
||||
nil [0]
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_aref_3
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]' for nil:NilClass
|
||||
END
|
||||
|
||||
nil [
|
||||
0
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_aref_4
|
||||
v = Object.new
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]' for #{ v.inspect }
|
||||
|
||||
v &.[](0)
|
||||
^^^^
|
||||
END
|
||||
|
||||
v &.[](0)
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_aset
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]=' for nil:NilClass
|
||||
|
||||
nil.[]=
|
||||
^^^^
|
||||
END
|
||||
|
||||
nil.[]=
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_op_asgn
|
||||
v = nil
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
v += 42
|
||||
^
|
||||
END
|
||||
|
||||
v += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_special_call_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `call' for nil:NilClass
|
||||
END
|
||||
|
||||
nil.()
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_special_call_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `call' for nil:NilClass
|
||||
END
|
||||
|
||||
nil.(42)
|
||||
end
|
||||
end
|
||||
|
||||
def test_CALL_send
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
nil.send(:foo, 42)
|
||||
^^^^^
|
||||
END
|
||||
|
||||
nil.send(:foo, 42)
|
||||
end
|
||||
end
|
||||
|
||||
def test_ATTRASGN_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]=' for nil:NilClass
|
||||
|
||||
nil [ ] = 42
|
||||
^^^^^
|
||||
END
|
||||
|
||||
nil [ ] = 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_ATTRASGN_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]=' for nil:NilClass
|
||||
|
||||
nil [0] = 42
|
||||
^^^^^
|
||||
END
|
||||
|
||||
nil [0] = 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_ATTRASGN_3
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo=' for nil:NilClass
|
||||
|
||||
nil.foo = 42
|
||||
^^^^^^
|
||||
END
|
||||
|
||||
nil.foo = 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OPCALL_binary_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
nil + 42
|
||||
^
|
||||
END
|
||||
|
||||
nil + 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OPCALL_binary_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
nil + # comment
|
||||
^
|
||||
END
|
||||
|
||||
nil + # comment
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OPCALL_unary
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+@' for nil:NilClass
|
||||
|
||||
+ nil
|
||||
^
|
||||
END
|
||||
|
||||
+ nil
|
||||
end
|
||||
end
|
||||
|
||||
def test_FCALL_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
nil.instance_eval { foo() }
|
||||
^^^
|
||||
END
|
||||
|
||||
nil.instance_eval { foo() }
|
||||
end
|
||||
end
|
||||
|
||||
def test_FCALL_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
nil.instance_eval { foo(42) }
|
||||
^^^
|
||||
END
|
||||
|
||||
nil.instance_eval { foo(42) }
|
||||
end
|
||||
end
|
||||
|
||||
def test_VCALL_2
|
||||
assert_error_message(NameError, <<~END) do
|
||||
undefined local variable or method `foo' for nil:NilClass
|
||||
|
||||
nil.instance_eval { foo }
|
||||
^^^
|
||||
END
|
||||
|
||||
nil.instance_eval { foo }
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_aref_1
|
||||
v = nil
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]' for nil:NilClass
|
||||
|
||||
v [0] += 42
|
||||
^^^
|
||||
END
|
||||
|
||||
v [0] += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_aref_2
|
||||
v = nil
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]' for nil:NilClass
|
||||
|
||||
v [0] += # comment
|
||||
^^^
|
||||
END
|
||||
|
||||
v [0] += # comment
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_aref_3
|
||||
v = nil
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]' for nil:NilClass
|
||||
END
|
||||
|
||||
v [
|
||||
0
|
||||
] += # comment
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_op_1
|
||||
v = Object.new
|
||||
def v.[](x); nil; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
v [0] += 42
|
||||
^
|
||||
END
|
||||
|
||||
v [0] += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_op_2
|
||||
v = Object.new
|
||||
def v.[](x); nil; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
v [0 ] += # comment
|
||||
^
|
||||
END
|
||||
|
||||
v [0 ] += # comment
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_op_3
|
||||
v = Object.new
|
||||
def v.[](x); nil; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
END
|
||||
|
||||
v [
|
||||
0
|
||||
] +=
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_aset_1
|
||||
v = Object.new
|
||||
def v.[](x); 1; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]=' for #{ v.inspect }
|
||||
|
||||
v [0] += 42
|
||||
^^^^^^
|
||||
END
|
||||
|
||||
v [0] += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_aset_2
|
||||
v = Object.new
|
||||
def v.[](x); 1; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]=' for #{ v.inspect }
|
||||
|
||||
v [0] += # comment
|
||||
^^^^^^
|
||||
END
|
||||
|
||||
v [0] += # comment
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN1_aset_3
|
||||
v = Object.new
|
||||
def v.[](x); 1; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `[]=' for #{ v.inspect }
|
||||
END
|
||||
|
||||
v [
|
||||
0
|
||||
] +=
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN2_read_1
|
||||
v = nil
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
v.foo += 42
|
||||
^^^^
|
||||
END
|
||||
|
||||
v.foo += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN2_read_2
|
||||
v = nil
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo' for nil:NilClass
|
||||
|
||||
v.foo += # comment
|
||||
^^^^
|
||||
END
|
||||
|
||||
v.foo += # comment
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN2_op_1
|
||||
v = Object.new
|
||||
def v.foo; nil; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
v.foo += 42
|
||||
^
|
||||
END
|
||||
|
||||
v.foo += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN2_op_2
|
||||
v = Object.new
|
||||
def v.foo; nil; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
v.foo += # comment
|
||||
^
|
||||
END
|
||||
|
||||
v.foo += # comment
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN2_write_1
|
||||
v = Object.new
|
||||
def v.foo; 1; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo=' for #{ v.inspect }
|
||||
|
||||
v.foo += 42
|
||||
^^^^^^^
|
||||
END
|
||||
|
||||
v.foo += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_ASGN2_write_2
|
||||
v = Object.new
|
||||
def v.foo; 1; end
|
||||
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `foo=' for #{ v.inspect }
|
||||
|
||||
v.foo += # comment
|
||||
^^^^^^^
|
||||
END
|
||||
|
||||
v.foo += # comment
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
def test_CONST
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant ErrorSquiggleTest::NotDefined
|
||||
|
||||
1 + NotDefined + 1
|
||||
^^^^^^^^^^
|
||||
END
|
||||
|
||||
1 + NotDefined + 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_COLON2_1
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant ErrorSquiggleTest::NotDefined
|
||||
|
||||
ErrorSquiggleTest::NotDefined
|
||||
^^^^^^^^^^^^
|
||||
END
|
||||
|
||||
ErrorSquiggleTest::NotDefined
|
||||
end
|
||||
end
|
||||
|
||||
def test_COLON2_2
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant ErrorSquiggleTest::NotDefined
|
||||
|
||||
NotDefined
|
||||
^^^^^^^^^^
|
||||
END
|
||||
|
||||
ErrorSquiggleTest::
|
||||
NotDefined
|
||||
end
|
||||
end
|
||||
|
||||
def test_COLON3
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant NotDefined
|
||||
|
||||
::NotDefined
|
||||
^^^^^^^^^^^^
|
||||
END
|
||||
|
||||
::NotDefined
|
||||
end
|
||||
end
|
||||
|
||||
module OP_CDECL_TEST
|
||||
Nil = nil
|
||||
end
|
||||
|
||||
def test_OP_CDECL_read_1
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant ErrorSquiggleTest::OP_CDECL_TEST::NotDefined
|
||||
|
||||
OP_CDECL_TEST::NotDefined += 1
|
||||
^^^^^^^^^^^^
|
||||
END
|
||||
|
||||
OP_CDECL_TEST::NotDefined += 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_CDECL_read_2
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant ErrorSquiggleTest::OP_CDECL_TEST::NotDefined
|
||||
|
||||
OP_CDECL_TEST::NotDefined += # comment
|
||||
^^^^^^^^^^^^
|
||||
END
|
||||
|
||||
OP_CDECL_TEST::NotDefined += # comment
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_CDECL_read_3
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant ErrorSquiggleTest::OP_CDECL_TEST::NotDefined
|
||||
END
|
||||
|
||||
OP_CDECL_TEST::
|
||||
NotDefined += 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_CDECL_op_1
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
OP_CDECL_TEST::Nil += 1
|
||||
^
|
||||
END
|
||||
|
||||
OP_CDECL_TEST::Nil += 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_CDECL_op_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
OP_CDECL_TEST::Nil += # comment
|
||||
^
|
||||
END
|
||||
|
||||
OP_CDECL_TEST::Nil += # comment
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_CDECL_op_3
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for nil:NilClass
|
||||
|
||||
Nil += 1
|
||||
^
|
||||
END
|
||||
|
||||
OP_CDECL_TEST::
|
||||
Nil += 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_CDECL_toplevel_1
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant NotDefined
|
||||
|
||||
::NotDefined += 1
|
||||
^^^^^^^^^^^^
|
||||
END
|
||||
|
||||
::NotDefined += 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_OP_CDECL_toplevel_2
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `+' for ErrorSquiggleTest:Class
|
||||
|
||||
::ErrorSquiggleTest += 1
|
||||
^
|
||||
END
|
||||
|
||||
::ErrorSquiggleTest += 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_explicit_raise_name_error
|
||||
assert_error_message(NameError, <<~END) do
|
||||
NameError
|
||||
|
||||
raise NameError
|
||||
^^^^^
|
||||
END
|
||||
|
||||
raise NameError
|
||||
end
|
||||
end
|
||||
|
||||
def test_explicit_raise_no_method_error
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
NoMethodError
|
||||
|
||||
raise NoMethodError
|
||||
^^^^^
|
||||
END
|
||||
|
||||
raise NoMethodError
|
||||
end
|
||||
end
|
||||
|
||||
def test_const_get
|
||||
assert_error_message(NameError, <<~END) do
|
||||
uninitialized constant ErrorSquiggleTest::NotDefined
|
||||
|
||||
ErrorSquiggleTest.const_get(:NotDefined)
|
||||
^^^^^^^^^^
|
||||
END
|
||||
|
||||
ErrorSquiggleTest.const_get(:NotDefined)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_variable_get
|
||||
b = binding
|
||||
assert_error_message(NameError, <<~END) do
|
||||
local variable `foo' is not defined for #{ b.inspect }
|
||||
|
||||
b.local_variable_get(:foo)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
END
|
||||
|
||||
b.local_variable_get(:foo)
|
||||
end
|
||||
end
|
||||
|
||||
def test_multibyte
|
||||
assert_error_message(NoMethodError, <<~END) do
|
||||
undefined method `あいうえお' for nil:NilClass
|
||||
|
||||
nil.あいうえお
|
||||
^^^^^^
|
||||
END
|
||||
|
||||
nil.あいうえお
|
||||
end
|
||||
end
|
||||
|
||||
if false
|
||||
|
||||
def test_args_CALL_1
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
nil can't be coerced into Integer
|
||||
|
||||
1.+(nil)
|
||||
^^^
|
||||
END
|
||||
|
||||
1.+(nil)
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_CALL_2
|
||||
v = []
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
no implicit conversion from nil to integer
|
||||
|
||||
v[nil]
|
||||
^^^
|
||||
END
|
||||
|
||||
v[nil]
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_ATTRASGN_1
|
||||
v = []
|
||||
assert_error_message(ArgumentError, <<~END) do
|
||||
wrong number of arguments (given 1, expected 2..3)
|
||||
|
||||
v [ ] = 1
|
||||
^^^^^^
|
||||
END
|
||||
|
||||
v [ ] = 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_ATTRASGN_2
|
||||
v = []
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
no implicit conversion from nil to integer
|
||||
|
||||
v [nil] = 1
|
||||
^^^^^^^^
|
||||
END
|
||||
|
||||
v [nil] = 1
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_ATTRASGN_3
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
no implicit conversion of String into Integer
|
||||
|
||||
$stdin.lineno = "str"
|
||||
^^^^^
|
||||
END
|
||||
|
||||
$stdin.lineno = "str"
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_OPCALL
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
nil can't be coerced into Integer
|
||||
|
||||
1 + nil
|
||||
^^^
|
||||
END
|
||||
|
||||
1 + nil
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_FCALL_1
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
no implicit conversion of Symbol into String
|
||||
|
||||
"str".instance_eval { gsub("foo", :sym) }
|
||||
^^^^^^^^^^^
|
||||
END
|
||||
|
||||
"str".instance_eval { gsub("foo", :sym) }
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_FCALL_2
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
no implicit conversion of Symbol into String
|
||||
|
||||
"str".instance_eval { gsub "foo", :sym }
|
||||
^^^^^^^^^^^
|
||||
END
|
||||
|
||||
"str".instance_eval { gsub "foo", :sym }
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_OP_ASGN1_aref_1
|
||||
v = []
|
||||
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
no implicit conversion from nil to integer
|
||||
|
||||
v [nil] += 42
|
||||
^^^^^^^^^^
|
||||
END
|
||||
|
||||
v [nil] += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_OP_ASGN1_aref_2
|
||||
v = []
|
||||
|
||||
assert_error_message(ArgumentError, <<~END) do
|
||||
wrong number of arguments (given 0, expected 1..2)
|
||||
|
||||
v [ ] += 42
|
||||
^^^^^^^^
|
||||
END
|
||||
|
||||
v [ ] += 42
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_OP_ASGN1_op
|
||||
v = [1]
|
||||
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
nil can't be coerced into Integer
|
||||
|
||||
v [0] += nil
|
||||
^^^^^^^^^
|
||||
END
|
||||
|
||||
v [0] += nil
|
||||
end
|
||||
end
|
||||
|
||||
def test_args_OP_ASGN2
|
||||
v = Object.new
|
||||
def v.foo; 1; end
|
||||
|
||||
assert_error_message(TypeError, <<~END) do
|
||||
nil can't be coerced into Integer
|
||||
|
||||
v.foo += nil
|
||||
^^^
|
||||
END
|
||||
|
||||
v.foo += nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -112,7 +112,7 @@ module MarshalTestLib
|
|||
marshal_equal(Exception.new('foo')) {|o| o.message}
|
||||
obj = Object.new
|
||||
e = assert_raise(NoMethodError) {obj.no_such_method()}
|
||||
marshal_equal(e) {|o| o.message}
|
||||
marshal_equal(e) {|o| o.message.lines.first.chomp}
|
||||
end
|
||||
|
||||
def test_exception_subclass
|
||||
|
|
|
@ -817,7 +817,7 @@ class TestMarshal < Test::Unit::TestCase
|
|||
nameerror_test
|
||||
rescue NameError => e
|
||||
e2 = Marshal.load(Marshal.dump(e))
|
||||
assert_equal(e.message, e2.message)
|
||||
assert_equal(e.message.lines.first.chomp, e2.message.lines.first)
|
||||
assert_equal(e.name, e2.name)
|
||||
assert_equal(e.backtrace, e2.backtrace)
|
||||
assert_nil(e2.backtrace_locations) # temporal
|
||||
|
|
|
@ -267,7 +267,7 @@ class TestModule < Test::Unit::TestCase
|
|||
].each do |name, msg|
|
||||
expected = "wrong constant name %s" % name
|
||||
msg = "#{msg}#{': ' if msg}wrong constant name #{name.dump}"
|
||||
assert_raise_with_message(NameError, expected, "#{msg} to #{m}") do
|
||||
assert_raise_with_message(NameError, Regexp.compile(Regexp.quote(expected)), "#{msg} to #{m}") do
|
||||
yield name
|
||||
end
|
||||
end
|
||||
|
|
|
@ -151,6 +151,6 @@ class TestNameError < Test::Unit::TestCase
|
|||
error = assert_raise(NameError) do
|
||||
receiver::FOO
|
||||
end
|
||||
assert_equal "uninitialized constant #{'A' * 120}::FOO", error.message
|
||||
assert_match /\Auninitialized constant #{'A' * 120}::FOO$/, error.message
|
||||
end
|
||||
end
|
||||
|
|
|
@ -86,7 +86,7 @@ class TestNoMethodError < Test::Unit::TestCase
|
|||
str = "\u2600"
|
||||
id = :"\u2604"
|
||||
msg = "undefined method `#{id}' for \"#{str}\":String"
|
||||
assert_raise_with_message(NoMethodError, msg, bug3237) do
|
||||
assert_raise_with_message(NoMethodError, Regexp.compile(Regexp.quote(msg)), bug3237) do
|
||||
str.__send__(id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -777,7 +777,7 @@ class TestObject < Test::Unit::TestCase
|
|||
e = assert_raise(NoMethodError) {
|
||||
o.never_defined_test_no_superclass_method
|
||||
}
|
||||
assert_equal(m1, e.message, bug2312)
|
||||
assert_equal(m1.lines.first, e.message.lines.first, bug2312)
|
||||
end
|
||||
|
||||
def test_superclass_method
|
||||
|
|
Loading…
Reference in a new issue