diff options
Diffstat (limited to 'test/ruby/test_parse.rb')
| -rw-r--r-- | test/ruby/test_parse.rb | 162 |
1 files changed, 126 insertions, 36 deletions
diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index b8de2ba952..def41d6017 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -2,6 +2,7 @@ # frozen_string_literal: false require 'test/unit' require 'stringio' +require_relative '../lib/parser_support' class TestParse < Test::Unit::TestCase def setup @@ -185,6 +186,15 @@ class TestParse < Test::Unit::TestCase end; end + c = Class.new + c.freeze + assert_valid_syntax("#{<<~"begin;"}\n#{<<~'end;'}") do + begin; + c::FOO &= p 1 + ::FOO &= p 1 + end; + end + assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /Can't set variable/) do begin; $1 &= 1 @@ -342,6 +352,21 @@ class TestParse < Test::Unit::TestCase assert_equal("foobar", b) end + def test_call_command + a = b = nil + o = Object.new + def o.m(*arg); proc {|a| arg.join + a }; end + + assert_nothing_raised do + o.instance_eval <<-END, __FILE__, __LINE__+1 + a = o.m "foo", "bar" do end.("buz") + b = o.m "foo", "bar" do end::("buz") + END + end + assert_equal("foobarbuz", a) + assert_equal("foobarbuz", b) + end + def test_xstring assert_raise(Errno::ENOENT) do eval("``") @@ -463,6 +488,14 @@ class TestParse < Test::Unit::TestCase assert_parse_error(%q[def ((%w();1)).foo; end], msg) assert_parse_error(%q[def ("#{42}").foo; end], msg) assert_parse_error(%q[def (:"#{42}").foo; end], msg) + assert_parse_error(%q[def ([]).foo; end], msg) + assert_parse_error(%q[def ([1]).foo; end], msg) + assert_parse_error(%q[def (__FILE__).foo; end], msg) + assert_parse_error(%q[def (__LINE__).foo; end], msg) + assert_parse_error(%q[def (__ENCODING__).foo; end], msg) + assert_parse_error(%q[def __FILE__.foo; end], msg) + assert_parse_error(%q[def __LINE__.foo; end], msg) + assert_parse_error(%q[def __ENCODING__.foo; end], msg) end def test_flip_flop @@ -512,12 +545,12 @@ class TestParse < Test::Unit::TestCase def t.dummy(_) end - assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /block arg given in index/) + assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /block arg given in index assignment/) begin; t[42, &blk] ||= 42 end; - assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /block arg given in index/) + assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /block arg given in index assignment/) begin; t[42, &blk] ||= t.dummy 42 # command_asgn test end; @@ -555,34 +588,42 @@ class TestParse < Test::Unit::TestCase mesg = 'from the backslash through the invalid char' e = assert_syntax_error('"\xg1"', /hex escape/) - assert_equal(' ^~'"\n", e.message.lines.last, mesg) + assert_match(/(^|\| ) \^~(?!~)/, e.message.lines.last, mesg) e = assert_syntax_error('"\u{1234"', 'unterminated Unicode escape') - assert_equal(' ^'"\n", e.message.lines.last, mesg) + assert_match(/(^|\| ) \^(?!~)/, e.message.lines.last, mesg) e = assert_syntax_error('"\u{xxxx}"', 'invalid Unicode escape') - assert_equal(' ^'"\n", e.message.lines.last, mesg) + assert_match(/(^|\| ) \^(?!~)/, e.message.lines.last, mesg) e = assert_syntax_error('"\u{xxxx', 'Unicode escape') - assert_pattern_list([ - /.*: invalid Unicode escape\n.*\n/, - / \^/, - /\n/, - /.*: unterminated Unicode escape\n.*\n/, - / \^/, - /\n/, - /.*: unterminated string.*\n.*\n/, - / \^\n/, - ], e.message) + if e.message.lines.first == "#{__FILE__}:#{__LINE__ - 1}: syntax errors found\n" + assert_pattern_list([ + /\s+\| \^ unterminated string;.+\n/, + /\s+\| \^ unterminated Unicode escape\n/, + /\s+\| \^ invalid Unicode escape sequence\n/, + ], e.message.lines[2..-1].join) + else + assert_pattern_list([ + /.*: invalid Unicode escape\n.*\n/, + / \^/, + /\n/, + /.*: unterminated Unicode escape\n.*\n/, + / \^/, + /\n/, + /.*: unterminated string.*\n.*\n/, + / \^\n/, + ], e.message) + end e = assert_syntax_error('"\M1"', /escape character syntax/) - assert_equal(' ^~~'"\n", e.message.lines.last, mesg) + assert_match(/(^|\| ) \^~~(?!~)/, e.message.lines.last, mesg) e = assert_syntax_error('"\C1"', /escape character syntax/) - assert_equal(' ^~~'"\n", e.message.lines.last, mesg) + assert_match(/(^|\| ) \^~~(?!~)/, e.message.lines.last, mesg) src = '"\xD0\u{90'"\n""000000000000000000000000" - assert_syntax_error(src, /:#{__LINE__}: unterminated/o) + assert_syntax_error(src, /(:#{__LINE__}:|> #{__LINE__} \|.+) unterminated/om) assert_syntax_error('"\u{100000000}"', /invalid Unicode escape/) assert_equal("", eval('"\u{}"')) @@ -605,22 +646,22 @@ class TestParse < Test::Unit::TestCase assert_syntax_error("\"\\C-\\M-\x01\"", 'Invalid escape character syntax') e = assert_syntax_error('"\c\u0000"', 'Invalid escape character syntax') - assert_equal(' ^~~~'"\n", e.message.lines.last) + assert_match(/(^|\| ) \^~~~(?!~)/, e.message.lines.last) e = assert_syntax_error('"\c\U0000"', 'Invalid escape character syntax') - assert_equal(' ^~~~'"\n", e.message.lines.last) + assert_match(/(^|\| ) \^~~~(?!~)/, e.message.lines.last) e = assert_syntax_error('"\C-\u0000"', 'Invalid escape character syntax') - assert_equal(' ^~~~~'"\n", e.message.lines.last) + assert_match(/(^|\| ) \^~~~~(?!~)/, e.message.lines.last) e = assert_syntax_error('"\C-\U0000"', 'Invalid escape character syntax') - assert_equal(' ^~~~~'"\n", e.message.lines.last) + assert_match(/(^|\| ) \^~~~~(?!~)/, e.message.lines.last) e = assert_syntax_error('"\M-\u0000"', 'Invalid escape character syntax') - assert_equal(' ^~~~~'"\n", e.message.lines.last) + assert_match(/(^|\| ) \^~~~~(?!~)/, e.message.lines.last) e = assert_syntax_error('"\M-\U0000"', 'Invalid escape character syntax') - assert_equal(' ^~~~~'"\n", e.message.lines.last) + assert_match(/(^|\| ) \^~~~~(?!~)/, e.message.lines.last) e = assert_syntax_error(%["\\C-\u3042"], 'Invalid escape character syntax') - assert_match(/^\s \^(?# \\ ) ~(?# C ) ~(?# - ) ~+(?# U+3042 )$/x, e.message.lines.last) + assert_match(/(^|\|\s)\s \^(?# \\ ) ~(?# C ) ~(?# - ) ~+(?# U+3042 )($|\s)/x, e.message.lines.last) assert_not_include(e.message, "invalid multibyte char") end @@ -637,6 +678,8 @@ class TestParse < Test::Unit::TestCase assert_equal("\u{1234}", eval('?\u{1234}')) assert_equal("\u{1234}", eval('?\u1234')) assert_syntax_error('?\u{41 42}', 'Multiple codepoints at single character literal') + assert_syntax_error("?and", /unexpected '\?'/) + assert_syntax_error("?\u1234and", /unexpected '\?'/) e = assert_syntax_error('"#{?\u123}"', 'invalid Unicode escape') assert_not_match(/end-of-input/, e.message) @@ -875,7 +918,8 @@ x = __ENCODING__ $test_parse_foobarbazqux = nil assert_equal(nil, $&) assert_equal(nil, eval('alias $& $preserve_last_match')) - assert_syntax_error('a = $#', /as a global variable name\na = \$\#\n \^~$/) + assert_syntax_error('a = $#', /as a global variable name/) + assert_syntax_error('a = $#', /a = \$\#\n(^|.+?\| ) \^~(?!~)/) end def test_invalid_instance_variable @@ -941,6 +985,7 @@ x = __ENCODING__ assert_nil assert_warning(useless_use) {eval("true; nil")} assert_nil assert_warning(useless_use) {eval("false; nil")} assert_nil assert_warning(useless_use) {eval("defined?(1); nil")} + assert_nil assert_warning(useless_use) {eval("begin; ensure; x; end")} assert_equal 1, x assert_syntax_error("1; next; 2", /Invalid next/) @@ -1259,8 +1304,8 @@ x = __ENCODING__ assert_syntax_error("def f r:def d; def f 0end", /unexpected/) end; - assert_syntax_error("def\nf(000)end", /^ \^~~/) - assert_syntax_error("def\nf(&0)end", /^ \^/) + assert_syntax_error("def\nf(000)end", /(^|\| ) \^~~/) + assert_syntax_error("def\nf(&0)end", /(^|\| ) \^/) end def test_method_location_in_rescue @@ -1336,17 +1381,21 @@ x = __ENCODING__ end def test_unexpected_token_after_numeric - assert_syntax_error('0000xyz', /^ \^~~\Z/) - assert_syntax_error('1.2i1.1', /^ \^~~\Z/) - assert_syntax_error('1.2.3', /^ \^~\Z/) + assert_syntax_error('0000xyz', /(^|\| ) \^~~(?!~)/) + assert_syntax_error('1.2i1.1', /(^|\| ) \^~~(?!~)/) + assert_syntax_error('1.2.3', /(^|\| ) \^~(?!~)/) assert_syntax_error('1.', /unexpected end-of-input/) assert_syntax_error('1e', /expecting end-of-input/) end def test_truncated_source_line - e = assert_syntax_error("'0123456789012345678901234567890123456789' abcdefghijklmnopqrstuvwxyz0123456789 0123456789012345678901234567890123456789", + lineno = __LINE__ + 1 + e = assert_syntax_error("'0123456789012345678901234567890123456789' abcdefghijklmnopqrstuvwxyz0123456789 123456789012345678901234567890123456789", /unexpected local variable or method/) + line = e.message.lines[1] + line.delete_prefix!("> #{lineno} | ") if line.start_with?(">") + assert_operator(line, :start_with?, "...") assert_operator(line, :end_with?, "...\n") end @@ -1390,11 +1439,11 @@ x = __ENCODING__ end def test_unexpected_eof - assert_syntax_error('unless', /^ \^\Z/) + assert_syntax_error('unless', /(^|\| ) \^(?!~)/) end def test_location_of_invalid_token - assert_syntax_error('class xxx end', /^ \^~~\Z/) + assert_syntax_error('class xxx end', /(^|\| ) \^~~(?!~)/) end def test_whitespace_warning @@ -1510,7 +1559,7 @@ x = __ENCODING__ end def test_shareable_constant_value_simple - obj = [['unsharable_value']] + obj = [['unshareable_value']] a, b, c = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}") begin; # shareable_constant_value: experimental_everything @@ -1539,7 +1588,7 @@ x = __ENCODING__ assert_ractor_shareable(a) assert_not_ractor_shareable(obj) assert_equal obj, a - assert !obj.equal?(a) + assert_not_same obj, a bug_20339 = '[ruby-core:117186] [Bug #20339]' bug_20341 = '[ruby-core:117197] [Bug #20341]' @@ -1560,6 +1609,21 @@ x = __ENCODING__ assert_equal(2, b[1], bug_20341) end + def test_shareable_constant_value_literal_const_refs + a = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}") + begin; + # shareable_constant_value: literal + # [Bug #20668] + SOME_CONST = { + 'Object' => Object, + 'String' => String, + 'Array' => Array, + } + SOME_CONST + end; + assert_ractor_shareable(a) + end + def test_shareable_constant_value_nested a, b = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}") begin; @@ -1578,6 +1642,23 @@ x = __ENCODING__ assert_ractor_shareable(a[0]) end + def test_shareable_constant_value_hash_with_keyword_splat + a, b = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}") + begin; + # shareable_constant_value: experimental_everything + # [Bug #20927] + x = { x: {} } + y = { y: {} } + A = { **x } + B = { x: {}, **y } + [A, B] + end; + assert_ractor_shareable(a) + assert_ractor_shareable(b) + assert_equal({ x: {}}, a) + assert_equal({ x: {}, y: {}}, b) + end + def test_shareable_constant_value_unshareable_literal assert_raise_separately(Ractor::IsolationError, /unshareable object to C/, "#{<<~"begin;"}\n#{<<~'end;'}") @@ -1672,6 +1753,15 @@ x = __ENCODING__ end; end + def test_shareable_constant_value_massign + a = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}") + begin; + # shareable_constant_value: experimental_everything + A, = 1 + end; + assert_equal(1, a) + end + def test_if_after_class assert_valid_syntax('module if true; Object end::Kernel; end') assert_valid_syntax('module while true; break Object end::Kernel; end') |
