1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/test/ruby/test_parse.rb
nobu bc44acb5a3 parse.y: fix yyerror message
* parse.y (parser_yyerror): show the error line even if the error
  is at the end.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57073 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-12-14 04:35:28 +00:00

966 lines
21 KiB
Ruby

# coding: US-ASCII
# frozen_string_literal: false
require 'test/unit'
require 'stringio'
class TestParse < Test::Unit::TestCase
def setup
@verbose = $VERBOSE
$VERBOSE = nil
end
def teardown
$VERBOSE = @verbose
end
def test_else_without_rescue
x = eval <<-END, nil, __FILE__, __LINE__+1
begin
else
42
end
END
assert_equal(42, x)
end
def test_alias_backref
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
alias $foo $1
END
end
end
def test_command_call
t = Object.new
def t.foo(x); x; end
a = false
b = c = d = true
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
a &&= t.foo 42
b &&= t.foo 42
c &&= t.foo nil
d &&= t.foo false
END
end
assert_equal([false, 42, nil, false], [a, b, c, d])
a = 3
assert_nothing_raised { eval("a &= t.foo 5") }
assert_equal(1, a)
a = [nil, nil, true, true]
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
a[0] ||= t.foo 42
a[1] &&= t.foo 42
a[2] ||= t.foo 42
a[3] &&= t.foo 42
END
end
assert_equal([42, nil, true, 42], a)
o = Object.new
class << o
attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux
end
o.foo = o.Foo = o::baz = nil
o.bar = o.Bar = o::qux = 1
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
o.foo ||= t.foo 42
o.bar &&= t.foo 42
o.Foo ||= t.foo 42
o.Bar &&= t.foo 42
o::baz ||= t.foo 42
o::qux &&= t.foo 42
END
end
assert_equal([42, 42], [o.foo, o.bar])
assert_equal([42, 42], [o.Foo, o.Bar])
assert_equal([42, 42], [o::baz, o::qux])
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
$1 ||= t.foo 42
END
end
def t.bar(x); x + yield; end
a = b = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
a = t.bar "foo" do
"bar"
end.gsub "ob", "OB"
b = t.bar "foo" do
"bar"
end::gsub "ob", "OB"
END
end
assert_equal("foOBar", a)
assert_equal("foOBar", b)
a = nil
assert_nothing_raised do
t.instance_eval <<-END, __FILE__, __LINE__+1
a = bar "foo" do "bar" end
END
end
assert_equal("foobar", a)
a = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
a = t::bar "foo" do "bar" end
END
end
assert_equal("foobar", a)
def t.baz(*r)
@baz = r + (block_given? ? [yield] : [])
end
assert_nothing_raised do
t.instance_eval "baz (1), 2"
end
assert_equal([1, 2], t.instance_eval { @baz })
end
def test_mlhs_node
c = Class.new
class << c
attr_accessor :foo, :bar, :Foo, :Bar
FOO = BAR = nil
end
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
c::foo, c::bar = 1, 2
c.Foo, c.Bar = 1, 2
c::FOO, c::BAR = 1, 2
END
end
assert_equal([1, 2], [c::foo, c::bar])
assert_equal([1, 2], [c.Foo, c.Bar])
assert_equal([1, 2], [c::FOO, c::BAR])
end
def test_dynamic_constant_assignment
assert_raise(SyntaxError) do
Object.new.instance_eval <<-END, __FILE__, __LINE__+1
def foo
self::FOO, self::BAR = 1, 2
::FOO, ::BAR = 1, 2
end
END
end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
$1, $2 = 1, 2
END
end
assert_raise(SyntaxError) do
Object.new.instance_eval <<-END, __FILE__, __LINE__+1
def foo
::FOO = 1
end
END
end
c = Class.new
assert_nothing_raised(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
if false
c::FOO &= 1
::FOO &= 1
end
END
end
c = Class.new
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
$1 &= 1
END
end
end
def test_class_module
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
class foo; end
END
end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
def foo
class Foo; end
module Bar; end
end
END
end
assert_nothing_raised(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
class Foo 1; end
END
end
end
def test_op_name
o = Object.new
def o.>(x); x; end
def o./(x); x; end
assert_nothing_raised do
o.instance_eval <<-END, __FILE__, __LINE__+1
undef >, /
END
end
end
def test_arg
o = Object.new
class << o
attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux
end
o.foo = o.Foo = o::baz = nil
o.bar = o.Bar = o::qux = 1
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
o.foo ||= 42
o.bar &&= 42
o.Foo ||= 42
o.Bar &&= 42
o::baz ||= 42
o::qux &&= 42
END
end
assert_equal([42, 42], [o.foo, o.bar])
assert_equal([42, 42], [o.Foo, o.Bar])
assert_equal([42, 42], [o::baz, o::qux])
a = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
a = -2.0 ** 2
END
end
assert_equal(-4.0, a)
end
def test_block_variable
o = Object.new
def o.foo(*r); yield(*r); end
a = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
o.foo 1 do|; a| a = 42 end
END
end
assert_nil(a)
end
def test_bad_arg
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
def foo(FOO); end
END
end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
def foo(@foo); end
END
end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
def foo($foo); end
END
end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
def foo(@@foo); end
END
end
o = Object.new
def o.foo(*r); yield(*r); end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
o.foo 1 {|; @a| @a = 42 }
END
end
end
def test_do_lambda
a = b = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
a = -> do
b = 42
end
END
end
a.call
assert_equal(42, b)
end
def test_block_call_colon2
o = Object.new
def o.foo(x); x + yield; end
a = b = nil
assert_nothing_raised do
o.instance_eval <<-END, __FILE__, __LINE__+1
a = foo 1 do 42 end.to_s
b = foo 1 do 42 end::to_s
END
end
assert_equal("43", a)
assert_equal("43", b)
end
def test_call_method
a = b = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
a = proc {|x| x + "bar" }.("foo")
b = proc {|x| x + "bar" }::("foo")
END
end
assert_equal("foobar", a)
assert_equal("foobar", b)
end
def test_xstring
assert_raise(Errno::ENOENT) do
eval("``")
end
end
def test_words
assert_equal([], %W( ))
end
def test_dstr
@@foo = 1
assert_equal("foo 1 bar", "foo #@@foo bar")
"1" =~ /(.)/
assert_equal("foo 1 bar", "foo #$1 bar")
end
def test_dstr_disallowed_variable
bug8375 = '[ruby-core:54885] [Bug #8375]'
%w[@ @1 @. @@ @@1 @@. $ $%].each do |src|
src = '#'+src+' '
str = assert_nothing_raised(SyntaxError, "#{bug8375} #{src.dump}") do
break eval('"'+src+'"')
end
assert_equal(src, str, bug8375)
end
end
def test_dsym
assert_nothing_raised { eval(':""') }
end
def assert_disallowed_variable(type, noname, *invalid)
assert_syntax_error(noname, "`#{noname}' without identifiers is not allowed as #{type} variable name")
invalid.each do |name|
assert_syntax_error(name, "`#{name}' is not allowed as #{type} variable name")
end
end
def test_disallowed_instance_variable
assert_disallowed_variable("an instance", *%w[@ @1 @.])
end
def test_disallowed_class_variable
assert_disallowed_variable("a class", *%w[@@ @@1 @@.])
end
def test_disallowed_gloal_variable
assert_disallowed_variable("a global", *%w[$ $%])
end
def test_arg2
o = Object.new
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
def o.foo(a=42,*r,z,&b); b.call(r.inject(a*1000+z*100, :+)); end
END
end
assert_equal(-1405, o.foo(1,2,3,4) {|x| -x })
assert_equal(-1302, o.foo(1,2,3) {|x| -x })
assert_equal(-1200, o.foo(1,2) {|x| -x })
assert_equal(-42100, o.foo(1) {|x| -x })
assert_raise(ArgumentError) { o.foo() }
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
def o.foo(a=42,z,&b); b.call(a*1000+z*100); end
END
end
assert_equal(-1200, o.foo(1,2) {|x| -x } )
assert_equal(-42100, o.foo(1) {|x| -x } )
assert_raise(ArgumentError) { o.foo() }
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
def o.foo(*r,z,&b); b.call(r.inject(z*100, :+)); end
END
end
assert_equal(-303, o.foo(1,2,3) {|x| -x } )
assert_equal(-201, o.foo(1,2) {|x| -x } )
assert_equal(-100, o.foo(1) {|x| -x } )
assert_raise(ArgumentError) { o.foo() }
end
def test_duplicate_argument
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
1.times {|&b?| }
END
end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
1.times {|a, a|}
END
end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
def foo(a, a); end
END
end
end
def test_define_singleton_error
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
def ("foo").foo; end
END
end
end
def test_backquote
t = Object.new
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
def t.`(x); "foo" + x + "bar"; end
END
end
a = b = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
a = t.` "zzz"
1.times {|;z| t.` ("zzz") }
END
t.instance_eval <<-END, __FILE__, __LINE__+1
b = `zzz`
END
end
assert_equal("foozzzbar", a)
assert_equal("foozzzbar", b)
end
def test_carrige_return
assert_equal(2, eval("1 +\r\n1"))
end
def test_string
assert_raise(SyntaxError) do
eval '"\xg1"'
end
assert_raise(SyntaxError) do
eval '"\u{1234"'
end
assert_raise(SyntaxError) do
eval '"\M1"'
end
assert_raise(SyntaxError) do
eval '"\C1"'
end
assert_equal("\x81", eval('"\C-\M-a"'))
assert_equal("\177", eval('"\c?"'))
end
def test_question
assert_raise(SyntaxError) { eval('?') }
assert_raise(SyntaxError) { eval('? ') }
assert_raise(SyntaxError) { eval("?\n") }
assert_raise(SyntaxError) { eval("?\t") }
assert_raise(SyntaxError) { eval("?\v") }
assert_raise(SyntaxError) { eval("?\r") }
assert_raise(SyntaxError) { eval("?\f") }
assert_equal("\u{1234}", eval("?\u{1234}"))
assert_equal("\u{1234}", eval('?\u{1234}'))
end
def test_percent
assert_equal(:foo, eval('%s(foo)'))
assert_raise(SyntaxError) { eval('%s') }
assert_raise(SyntaxError) { eval('%ss') }
assert_raise(SyntaxError) { eval('%z()') }
end
def test_symbol
bug = '[ruby-dev:41447]'
sym = "foo\0bar".to_sym
assert_nothing_raised(SyntaxError, bug) do
assert_equal(sym, eval(":'foo\0bar'"))
end
assert_nothing_raised(SyntaxError, bug) do
assert_equal(sym, eval(':"foo\u0000bar"'))
end
assert_nothing_raised(SyntaxError, bug) do
assert_equal(sym, eval(':"foo\u{0}bar"'))
end
end
def test_parse_string
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
/
END
end
end
def test_here_document
x = nil
assert_raise(SyntaxError) do
eval %Q(
<\<FOO
)
end
assert_nothing_raised(SyntaxError) do
x = eval %q(
<<FOO
#$
FOO
)
end
assert_equal "\#$\n", x
assert_raise(SyntaxError) do
eval %Q(
<\<\"
)
end
assert_raise(SyntaxError) do
eval %q(
<<``
)
end
assert_raise(SyntaxError) do
eval %q(
<<--
)
end
assert_nothing_raised(SyntaxError) do
x = eval %q(
<<FOO
#$
foo
FOO
)
end
assert_equal "\#$\nfoo\n", x
assert_nothing_raised do
eval "x = <<""FOO\r\n1\r\nFOO"
end
assert_equal("1\n", x)
end
def test_magic_comment
x = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
# coding = utf-8
x = __ENCODING__
END
end
assert_equal(Encoding.find("UTF-8"), x)
assert_raise(ArgumentError) do
eval <<-END, nil, __FILE__, __LINE__+1
# coding = foobarbazquxquux_dummy_enconding
x = __ENCODING__
END
end
end
def test_utf8_bom
x = nil
assert_nothing_raised do
eval "\xef\xbb\xbf x = __ENCODING__"
end
assert_equal(Encoding.find("UTF-8"), x)
assert_raise(NameError) { eval "\xef" }
end
def test_dot_in_next_line
x = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
x = 1
.to_s
END
end
assert_equal("1", x)
end
def test_pow_asgn
x = 3
assert_nothing_raised { eval("x **= 2") }
assert_equal(9, x)
end
def test_embedded_rd
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
=begin
END
end
end
def test_float
assert_equal(1.0/0, eval("1e10000"))
assert_raise(SyntaxError) { eval('1_E') }
assert_raise(SyntaxError) { eval('1E1E1') }
end
def test_global_variable
assert_equal(nil, eval('$-x'))
assert_equal(nil, eval('alias $preserve_last_match $&'))
assert_equal(nil, eval('alias $& $test_parse_foobarbazqux'))
$test_parse_foobarbazqux = nil
assert_equal(nil, $&)
assert_equal(nil, eval('alias $& $preserve_last_match'))
assert_raise(SyntaxError) { eval('$#') }
end
def test_invalid_instance_variable
assert_raise(SyntaxError) { eval('@#') }
assert_raise(SyntaxError) { eval('@') }
end
def test_invalid_class_variable
assert_raise(SyntaxError) { eval('@@1') }
assert_raise(SyntaxError) { eval('@@') }
end
def test_invalid_char
bug10117 = '[ruby-core:64243] [Bug #10117]'
invalid_char = /Invalid char `\\x01'/
x = x = 1
assert_in_out_err(%W"-e \x01x", "", [], invalid_char, bug10117)
assert_syntax_error("\x01x", invalid_char, bug10117)
assert_equal(nil, eval("\x04x"))
end
def test_literal_concat
x = x = "baz"
assert_equal("foobarbaz", eval('"foo" "bar#{x}"'))
end
def test_unassignable
assert_raise(SyntaxError) do
eval %q(self = 1)
end
assert_raise(SyntaxError) do
eval %q(nil = 1)
end
assert_raise(SyntaxError) do
eval %q(true = 1)
end
assert_raise(SyntaxError) do
eval %q(false = 1)
end
assert_raise(SyntaxError) do
eval %q(__FILE__ = 1)
end
assert_raise(SyntaxError) do
eval %q(__LINE__ = 1)
end
assert_raise(SyntaxError) do
eval %q(__ENCODING__ = 1)
end
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
def foo
FOO = 1
end
END
end
end
def test_block_dup
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
foo(&proc{}) {}
END
end
end
def test_set_backref
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
$& = 1
END
end
end
def test_arg_concat
o = Object.new
class << o; self; end.instance_eval do
define_method(:[]=) {|*r, &b| b.call(r) }
end
r = nil
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
o[&proc{|x| r = x }] = 1
END
end
assert_equal([1], r)
end
def test_void_expr_stmts_value
# This test checks if void contexts are warned correctly.
# Thus, warnings MUST NOT be suppressed.
$VERBOSE = true
stderr = $stderr
$stderr = StringIO.new("")
x = x = 1
assert_nil eval("x; nil")
assert_nil eval("1+1; nil")
assert_nil eval("TestParse; nil")
assert_nil eval("::TestParse; nil")
assert_nil eval("x..x; nil")
assert_nil eval("x...x; nil")
assert_nil eval("self; nil")
assert_nil eval("nil; nil")
assert_nil eval("true; nil")
assert_nil eval("false; nil")
assert_nil eval("defined?(1); nil")
assert_raise(SyntaxError) do
eval %q(1; next; 2)
end
assert_equal(13, $stderr.string.lines.to_a.size)
$stderr = stderr
end
def test_assign_in_conditional
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
(x, y = 1, 2) ? 1 : 2
END
end
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
if @x = true
1
else
2
end
END
end
end
def test_literal_in_conditional
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
"foo" ? 1 : 2
END
end
assert_nothing_raised do
x = "bar"
eval <<-END, nil, __FILE__, __LINE__+1
/foo#{x}baz/ ? 1 : 2
END
end
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
(true..false) ? 1 : 2
END
end
assert_nothing_raised do
eval <<-END, nil, __FILE__, __LINE__+1
("foo".."bar") ? 1 : 2
END
end
assert_nothing_raised do
x = x = "bar"
eval <<-END, nil, __FILE__, __LINE__+1
:"foo#{"x"}baz" ? 1 : 2
END
end
end
def test_no_blockarg
assert_raise(SyntaxError) do
eval <<-END, nil, __FILE__, __LINE__+1
yield(&:+)
END
end
end
def test_method_block_location
bug5614 = '[ruby-core:40936]'
expected = nil
e = assert_raise(NoMethodError) do
1.times do
expected = __LINE__+1
end.print do
#
end
end
actual = e.backtrace.first[/\A#{Regexp.quote(__FILE__)}:(\d+):/o, 1].to_i
assert_equal(expected, actual, bug5614)
end
def test_shadowing_variable
assert_warning(/shadowing outer local variable/) {eval("a=1; tap {|a|}")}
a = "\u{3042}"
assert_warning(/#{a}/o) {eval("#{a}=1; tap {|#{a}|}")}
end
def test_unused_variable
o = Object.new
assert_warning(/assigned but unused variable/) {o.instance_eval("def foo; a=1; nil; end")}
a = "\u{3042}"
assert_warning(/#{a}/) {o.instance_eval("def foo; #{a}=1; nil; end")}
end
def test_named_capture_conflict
a = 1
assert_warning('') {eval("a = 1; /(?<a>)/ =~ ''")}
a = "\u{3042}"
assert_warning('') {eval("#{a} = 1; /(?<#{a}>)/ =~ ''")}
end
def test_rescue_in_command_assignment
bug = '[ruby-core:75621] [Bug #12402]'
all_assertions(bug) do |a|
a.for("lhs = arg") do
v = bug
v = raise(bug) rescue "ok"
assert_equal("ok", v)
end
a.for("lhs op_asgn arg") do
v = 0
v += raise(bug) rescue 1
assert_equal(1, v)
end
a.for("lhs[] op_asgn arg") do
v = [0]
v[0] += raise(bug) rescue 1
assert_equal([1], v)
end
a.for("lhs.m op_asgn arg") do
k = Struct.new(:m)
v = k.new(0)
v.m += raise(bug) rescue 1
assert_equal(k.new(1), v)
end
a.for("lhs::m op_asgn arg") do
k = Struct.new(:m)
v = k.new(0)
v::m += raise(bug) rescue 1
assert_equal(k.new(1), v)
end
a.for("lhs.C op_asgn arg") do
k = Struct.new(:C)
v = k.new(0)
v.C += raise(bug) rescue 1
assert_equal(k.new(1), v)
end
a.for("lhs::C op_asgn arg") do
v = Class.new
v::C ||= raise(bug) rescue 1
assert_equal(1, v::C)
end
a.for("lhs = command") do
v = bug
v = raise bug rescue "ok"
assert_equal("ok", v)
end
a.for("lhs op_asgn command") do
v = 0
v += raise bug rescue 1
assert_equal(1, v)
end
a.for("lhs[] op_asgn command") do
v = [0]
v[0] += raise bug rescue 1
assert_equal([1], v)
end
a.for("lhs.m op_asgn command") do
k = Struct.new(:m)
v = k.new(0)
v.m += raise bug rescue 1
assert_equal(k.new(1), v)
end
a.for("lhs::m op_asgn command") do
k = Struct.new(:m)
v = k.new(0)
v::m += raise bug rescue 1
assert_equal(k.new(1), v)
end
a.for("lhs.C op_asgn command") do
k = Struct.new(:C)
v = k.new(0)
v.C += raise bug rescue 1
assert_equal(k.new(1), v)
end
a.for("lhs::C op_asgn command") do
v = Class.new
v::C ||= raise bug rescue 1
assert_equal(1, v::C)
end
end
end
def test_yyerror_at_eol
assert_syntax_error(" 0b", /\^/)
assert_syntax_error(" 0b\n", /\^/)
end
=begin
def test_past_scope_variable
assert_warning(/past scope/) {catch {|tag| eval("BEGIN{throw tag}; tap {a = 1}; a")}}
end
=end
end