summaryrefslogtreecommitdiff
path: root/test/ruby/test_syntax.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_syntax.rb')
-rw-r--r--test/ruby/test_syntax.rb210
1 files changed, 179 insertions, 31 deletions
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index 8f94ec71fc..b355128a73 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -139,6 +139,11 @@ class TestSyntax < Test::Unit::TestCase
inner(&)
end
assert_equal(10, all_kwrest(nil, nil, nil, nil, okw1: nil, okw2: nil){10})
+
+ def evaled(&)
+ eval("inner(&)")
+ end
+ assert_equal(1, evaled{1})
end;
end
@@ -156,8 +161,10 @@ class TestSyntax < Test::Unit::TestCase
def b(*); c(*) end
def c(*a); a end
def d(*); b(*, *) end
+ def e(*); eval("b(*)") end
assert_equal([1, 2], b(1, 2))
assert_equal([1, 2, 1, 2], d(1, 2))
+ assert_equal([1, 2], e(1, 2))
end;
end
@@ -177,10 +184,12 @@ class TestSyntax < Test::Unit::TestCase
def d(**); b(k: 1, **) end
def e(**); b(**, k: 1) end
def f(a: nil, **); b(**) end
+ def g(**); eval("b(**)") end
assert_equal({a: 1, k: 3}, b(a: 1, k: 3))
assert_equal({a: 1, k: 3}, d(a: 1, k: 3))
assert_equal({a: 1, k: 1}, e(a: 1, k: 3))
assert_equal({k: 3}, f(a: 1, k: 3))
+ assert_equal({a: 1, k: 3}, g(a: 1, k: 3))
end;
end
@@ -208,7 +217,7 @@ class TestSyntax < Test::Unit::TestCase
blocks = [['do end', 'do'], ['{}', 'brace']],
*|
[%w'. dot', %w':: colon'].product(methods, blocks) do |(c, n1), (m, n2), (b, n3)|
- m = m.tr_s('()', ' ').strip if n2 == 'do'
+ m = m.tr_s('()', ' ').strip if n3 == 'do'
name = "test_#{n3}_block_after_blockcall_#{n1}_#{n2}_arg"
code = "#{blockcall}#{c}#{m} #{b}"
define_method(name) {assert_valid_syntax(code, bug6115)}
@@ -330,7 +339,12 @@ class TestSyntax < Test::Unit::TestCase
bug10315 = '[ruby-core:65368] [Bug #10315]'
o = KW2.new
- assert_equal([23, 2], o.kw(**{k1: 22}, **{k1: 23}), bug10315)
+ begin
+ verbose_bak, $VERBOSE = $VERBOSE, nil
+ assert_equal([23, 2], eval("o.kw(**{k1: 22}, **{k1: 23})"), bug10315)
+ ensure
+ $VERBOSE = verbose_bak
+ end
h = {k3: 31}
assert_raise(ArgumentError) {o.kw(**h)}
@@ -392,12 +406,11 @@ class TestSyntax < Test::Unit::TestCase
end
def test_keyword_self_reference
- message = /circular argument reference - var/
- assert_syntax_error("def foo(var: defined?(var)) var end", message)
- assert_syntax_error("def foo(var: var) var end", message)
- assert_syntax_error("def foo(var: bar(var)) var end", message)
- assert_syntax_error("def foo(var: bar {var}) var end", message)
- assert_syntax_error("def foo(var: (1 in ^var)); end", message)
+ assert_valid_syntax("def foo(var: defined?(var)) var end")
+ assert_valid_syntax("def foo(var: var) var end")
+ assert_valid_syntax("def foo(var: bar(var)) var end")
+ assert_valid_syntax("def foo(var: bar {var}) var end")
+ assert_valid_syntax("def foo(var: (1 in ^var)); end")
o = Object.new
assert_warn("") do
@@ -423,6 +436,9 @@ class TestSyntax < Test::Unit::TestCase
assert_warn("") do
o.instance_eval("proc {|var: 1| var}")
end
+
+ o = Object.new
+ assert_nil(o.instance_eval("def foo(bar: bar) = bar; foo"))
end
def test_keyword_invalid_name
@@ -456,14 +472,13 @@ class TestSyntax < Test::Unit::TestCase
end
def test_optional_self_reference
- message = /circular argument reference - var/
- assert_syntax_error("def foo(var = defined?(var)) var end", message)
- assert_syntax_error("def foo(var = var) var end", message)
- assert_syntax_error("def foo(var = bar(var)) var end", message)
- assert_syntax_error("def foo(var = bar {var}) var end", message)
- assert_syntax_error("def foo(var = (def bar;end; var)) var end", message)
- assert_syntax_error("def foo(var = (def self.bar;end; var)) var end", message)
- assert_syntax_error("def foo(var = (1 in ^var)); end", message)
+ assert_valid_syntax("def foo(var = defined?(var)) var end")
+ assert_valid_syntax("def foo(var = var) var end")
+ assert_valid_syntax("def foo(var = bar(var)) var end")
+ assert_valid_syntax("def foo(var = bar {var}) var end")
+ assert_valid_syntax("def foo(var = (def bar;end; var)) var end")
+ assert_valid_syntax("def foo(var = (def self.bar;end; var)) var end")
+ assert_valid_syntax("def foo(var = (1 in ^var)); end")
o = Object.new
assert_warn("") do
@@ -489,6 +504,9 @@ class TestSyntax < Test::Unit::TestCase
assert_warn("") do
o.instance_eval("proc {|var = 1| var}")
end
+
+ o = Object.new
+ assert_nil(o.instance_eval("def foo(bar: bar) = bar; foo"))
end
def test_warn_grouped_expression
@@ -1241,6 +1259,52 @@ eom
assert_valid_syntax("a #\n#\n&.foo\n")
end
+ def test_fluent_and
+ assert_valid_syntax("a\n" "&& foo")
+ assert_valid_syntax("a\n" "and foo")
+
+ assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
+ begin;
+ a = true
+ if a
+ && (a = :ok; true)
+ a
+ end
+ end;
+
+ assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
+ begin;
+ a = true
+ if a
+ and (a = :ok; true)
+ a
+ end
+ end;
+ end
+
+ def test_fluent_or
+ assert_valid_syntax("a\n" "|| foo")
+ assert_valid_syntax("a\n" "or foo")
+
+ assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
+ begin;
+ a = false
+ if a
+ || (a = :ok; true)
+ a
+ end
+ end;
+
+ assert_equal(:ok, eval("#{<<~"begin;"}\n#{<<~'end;'}"))
+ begin;
+ a = false
+ if a
+ or (a = :ok; true)
+ a
+ end
+ end;
+ end
+
def test_safe_call_in_massign_lhs
assert_syntax_error("*a&.x=0", /multiple assignment destination/)
assert_syntax_error("a&.x,=0", /multiple assignment destination/)
@@ -1383,7 +1447,7 @@ eom
def test_block_after_cmdarg_in_paren
bug11873 = '[ruby-core:72482] [Bug #11873]'
- def bug11873.p(*);end;
+ def bug11873.p(*, &);end;
assert_raise(LocalJumpError, bug11873) do
bug11873.instance_eval do
@@ -1605,7 +1669,7 @@ eom
end
def test_invalid_jump
- assert_in_out_err(%w[-e redo], "", [], /^-e:1: /)
+ assert_in_out_err(%w[-e redo], "", [], /^-e:1: |~ Invalid redo/)
end
def test_keyword_not_parens
@@ -1776,15 +1840,12 @@ eom
assert_equal("class ok", k.rescued("ok"))
assert_equal("instance ok", k.new.rescued("ok"))
- # Current technical limitation: cannot prepend "private" or something for command endless def
- error = /(syntax error,|\^~*) unexpected string literal/
- error2 = /(syntax error,|\^~*) unexpected local variable or method/
- assert_syntax_error('private def foo = puts "Hello"', error)
- assert_syntax_error('private def foo() = puts "Hello"', error)
- assert_syntax_error('private def foo(x) = puts x', error2)
- assert_syntax_error('private def obj.foo = puts "Hello"', error)
- assert_syntax_error('private def obj.foo() = puts "Hello"', error)
- assert_syntax_error('private def obj.foo(x) = puts x', error2)
+ assert_valid_syntax('private def foo = puts "Hello"')
+ assert_valid_syntax('private def foo() = puts "Hello"')
+ assert_valid_syntax('private def foo(x) = puts x')
+ assert_valid_syntax('private def obj.foo = puts "Hello"')
+ assert_valid_syntax('private def obj.foo() = puts "Hello"')
+ assert_valid_syntax('private def obj.foo(x) = puts x')
end
def test_methoddef_in_cond
@@ -1825,6 +1886,10 @@ eom
assert_valid_syntax('a.b (;),(),()', bug19281)
end
+ def test_command_do_block_call_with_empty_args_brace_block
+ assert_valid_syntax('cmd 1, 2 do end.m() { blk_body }')
+ end
+
def test_numbered_parameter
assert_valid_syntax('proc {_1}')
assert_equal(3, eval('[1,2].then {_1+_2}'))
@@ -1907,6 +1972,7 @@ eom
assert_equal(4, eval('a=Object.new; def a.foo(it); it; end; a.foo(4)'))
assert_equal(5, eval('a=Object.new; def a.it; 5; end; a.it'))
assert_equal(6, eval('a=Class.new; a.class_eval{ def it; 6; end }; a.new.it'))
+ assert_equal([7, 8], eval('a=[]; [7].each { a << it; [8].each { a << it } }; a'))
assert_raise_with_message(NameError, /undefined local variable or method 'it'/) do
eval('it')
end
@@ -1923,6 +1989,28 @@ eom
end
assert_valid_syntax('proc {def foo(_);end;it}')
assert_syntax_error('p { [it **2] }', /unexpected \*\*/)
+ assert_equal(1, eval('1.then { raise rescue it }'))
+ assert_equal(2, eval('1.then { 2.then { raise rescue it } }'))
+ assert_equal(3, eval('3.then { begin; raise; rescue; it; end }'))
+ assert_equal(4, eval('4.tap { begin; raise ; rescue; raise rescue it; end; }'))
+ assert_equal(5, eval('a = 0; 5.then { begin; nil; ensure; a = it; end }; a'))
+ assert_equal(6, eval('a = 0; 6.then { begin; nil; rescue; ensure; a = it; end }; a'))
+ assert_equal(7, eval('a = 0; 7.then { begin; raise; ensure; a = it; end } rescue a'))
+ assert_equal(8, eval('a = 0; 8.then { begin; raise; rescue; ensure; a = it; end }; a'))
+ assert_equal(/9/, eval('9.then { /#{it}/o }'))
+ end
+
+ def test_it_with_splat_super_method
+ bug21256 = '[ruby-core:121592] [Bug #21256]'
+
+ a = Class.new do
+ define_method(:foo) { it }
+ end
+ b = Class.new(a) do
+ def foo(*args) = super
+ end
+
+ assert_equal(1, b.new.foo(1), bug21256)
end
def test_value_expr_in_condition
@@ -1955,16 +2043,23 @@ eom
assert_valid_syntax("def foo b = 1, ...; bar(...); end")
assert_valid_syntax("(def foo ...\n bar(...)\nend)")
assert_valid_syntax("(def foo ...; bar(...); end)")
+ assert_valid_syntax("def (1...).foo ...; bar(...); end")
+ assert_valid_syntax("def (tap{1...}).foo ...; bar(...); end")
assert_valid_syntax('def ==(...) end')
assert_valid_syntax('def [](...) end')
assert_valid_syntax('def nil(...) end')
assert_valid_syntax('def true(...) end')
assert_valid_syntax('def false(...) end')
+ assert_valid_syntax('->a=1...{}')
unexpected = /unexpected \.{3}/
assert_syntax_error('iter do |...| end', /unexpected/)
assert_syntax_error('iter {|...|}', /unexpected/)
assert_syntax_error('->... {}', unexpected)
assert_syntax_error('->(...) {}', unexpected)
+ assert_syntax_error('->a,... {}', unexpected)
+ assert_syntax_error('->(a,...) {}', unexpected)
+ assert_syntax_error('->a=1,... {}', unexpected)
+ assert_syntax_error('->(a=1,...) {}', unexpected)
assert_syntax_error('def foo(x, y, z) bar(...); end', /unexpected/)
assert_syntax_error('def foo(x, y, z) super(...); end', /unexpected/)
assert_syntax_error('def foo(...) yield(...); end', /unexpected/)
@@ -1988,9 +2083,11 @@ eom
end
obj4 = obj1.clone
obj5 = obj1.clone
+ obj6 = obj1.clone
obj1.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
obj4.instance_eval("def foo ...\n bar(...)\n""end", __FILE__, __LINE__)
obj5.instance_eval("def foo ...; bar(...); end", __FILE__, __LINE__)
+ obj6.instance_eval('def foo(...) eval("bar(...)") end', __FILE__, __LINE__)
klass = Class.new {
def foo(*args, **kws, &block)
@@ -2019,7 +2116,7 @@ eom
end
obj3.instance_eval('def foo(...) bar(...) end', __FILE__, __LINE__)
- [obj1, obj2, obj3, obj4, obj5].each do |obj|
+ [obj1, obj2, obj3, obj4, obj5, obj6].each do |obj|
assert_warning('') {
assert_equal([[1, 2, 3], {k1: 4, k2: 5}], obj.foo(1, 2, 3, k1: 4, k2: 5) {|*x| x})
}
@@ -2184,14 +2281,28 @@ eom
assert_syntax_error('def foo(...) super(1, ...) {}; end', /both block arg and actual block/)
end
+ def test_argument_forwarding_with_super_memory_leak
+ assert_no_memory_leak([], "#{<<-'begin;'}", "#{<<-'end;'}", rss: true)
+ code = proc do
+ eval("def foo(...) super(...) {}; end")
+ raise "unreachable"
+ rescue SyntaxError
+ end
+
+ 1_000.times(&code)
+ begin;
+ 100_000.times(&code)
+ end;
+ end
+
def test_class_module_Object_ancestors
- assert_separately([], <<-RUBY)
+ assert_ruby_status([], <<-RUBY)
m = Module.new
m::Bug18832 = 1
include m
class Bug18832; end
RUBY
- assert_separately([], <<-RUBY)
+ assert_ruby_status([], <<-RUBY)
m = Module.new
m::Bug18832 = 1
include m
@@ -2214,6 +2325,43 @@ eom
RUBY
end
+ def test_defined_in_short_circuit_if_condition
+ bug = '[ruby-core:20501]'
+ conds = [
+ "false && defined?(Some::CONSTANT)",
+ "true || defined?(Some::CONSTANT)",
+ "(false && defined?(Some::CONSTANT))", # parens exercise different code path
+ "(true || defined?(Some::CONSTANT))",
+ "@val && false && defined?(Some::CONSTANT)",
+ "@val || true || defined?(Some::CONSTANT)"
+ ]
+
+ conds.each do |cond|
+ code = %Q{
+ def my_method
+ var = "there"
+ if #{cond}
+ var = "here"
+ end
+ raise var
+ end
+ begin
+ my_method
+ rescue
+ print 'ok'
+ else
+ print 'ng'
+ end
+ }
+ # Invoke in a subprocess because the bug caused a segfault using the parse.y compiler.
+ # Don't use assert_separately because the bug was best reproducible in a clean slate,
+ # without test env loaded.
+ out, _err, status = EnvUtil.invoke_ruby(["--disable-gems"], code, true, false)
+ assert_predicate(status, :success?, bug)
+ assert_equal 'ok', out
+ end
+ end
+
private
def not_label(x) @result = x; @not_label ||= nil end
@@ -2248,7 +2396,7 @@ eom
end
end
- def caller_lineno(*)
+ def caller_lineno(*, &)
caller_locations(1, 1)[0].lineno
end
end