require 'test/unit' require_relative 'envutil' class TestSyntax < Test::Unit::TestCase def assert_syntax_files(test) srcdir = File.expand_path("../../..", __FILE__) srcdir = File.join(srcdir, test) assert_separately(%W[--disable-gem -r#{__dir__}/envutil - #{srcdir}], __FILE__, __LINE__, <<-'eom', timeout: Float::INFINITY) dir = ARGV.shift for script in Dir["#{dir}/**/*.rb"].sort assert_valid_syntax(IO::read(script), script) end eom end def test_syntax_lib; assert_syntax_files("lib"); end def test_syntax_sample; assert_syntax_files("sample"); end def test_syntax_ext; assert_syntax_files("ext"); end def test_syntax_test; assert_syntax_files("test"); end def test_defined_empty_argument bug8220 = '[ruby-core:53999] [Bug #8220]' assert_ruby_status(%w[--disable-gem], 'puts defined? ()', bug8220) end def test_must_ascii_compatible require 'tempfile' f = Tempfile.new("must_ac_") Encoding.list.each do |enc| next unless enc.ascii_compatible? make_tmpsrc(f, "# -*- coding: #{enc.name} -*-") assert_nothing_raised(ArgumentError, enc.name) {load(f.path)} end Encoding.list.each do |enc| next if enc.ascii_compatible? make_tmpsrc(f, "# -*- coding: #{enc.name} -*-") assert_raise(ArgumentError, enc.name) {load(f.path)} end ensure f.close! if f end def test_script_lines require 'tempfile' f = Tempfile.new("bug4361_") bug4361 = '[ruby-dev:43168]' with_script_lines do |debug_lines| Encoding.list.each do |enc| next unless enc.ascii_compatible? make_tmpsrc(f, "# -*- coding: #{enc.name} -*-\n#----------------") load(f.path) assert_equal([f.path], debug_lines.keys) assert_equal([enc, enc], debug_lines[f.path].map(&:encoding), bug4361) end end ensure f.close! if f end def test_newline_in_block_parameters bug = '[ruby-dev:45292]' ["", "a", "a, b"].product(["", ";x", [";", "x"]]) do |params| params = ["|", *params, "|"].join("\n") assert_valid_syntax("1.times{#{params}}", __FILE__, "#{bug} #{params.inspect}") end end tap do |_, bug6115 = '[ruby-dev:45308]', blockcall = '["elem"].each_with_object [] do end', methods = [['map', 'no'], ['inject([])', 'with']], 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' name = "test_#{n3}_block_after_blockcall_#{n1}_#{n2}_arg" code = "#{blockcall}#{c}#{m} #{b}" define_method(name) {assert_valid_syntax(code, bug6115)} end end def test_do_block_in_cmdarg bug9726 = '[ruby-core:61950] [Bug #9726]' assert_valid_syntax("tap (proc do end)", __FILE__, bug9726) end def test_keyword_rest bug5989 = '[ruby-core:42455]' assert_valid_syntax("def kwrest_test(**a) a; end", __FILE__, bug5989) assert_valid_syntax("def kwrest_test2(**a, &b) end", __FILE__, bug5989) o = Object.new def o.kw(**a) a end assert_equal({}, o.kw, bug5989) assert_equal({foo: 1}, o.kw(foo: 1), bug5989) assert_equal({foo: 1, bar: 2}, o.kw(foo: 1, bar: 2), bug5989) EnvUtil.under_gc_stress do eval("def o.m(k: 0) k end") end assert_equal(42, o.m(k: 42), '[ruby-core:45744]') bug7922 = '[ruby-core:52744] [Bug #7922]' def o.bug7922(**) end assert_nothing_raised(ArgumentError, bug7922) {o.bug7922(foo: 42)} end def test_keyword_splat assert_valid_syntax("foo(**h)", __FILE__) o = Object.new def o.kw(k1: 1, k2: 2) [k1, k2] end h = {k1: 11, k2: 12} assert_equal([11, 12], o.kw(**h)) assert_equal([11, 12], o.kw(k2: 22, **h)) assert_equal([11, 22], o.kw(**h, **{k2: 22})) assert_equal([11, 12], o.kw(**{k2: 22}, **h)) bug10315 = '[ruby-core:65368] [Bug #10315]' assert_equal([23, 2], o.kw(**{k1: 22}, **{k1: 23}), bug10315) h = {k3: 31} assert_raise(ArgumentError) {o.kw(**h)} h = {"k1"=>11, k2: 12} assert_raise(TypeError) {o.kw(**h)} bug10315 = '[ruby-core:65625] [Bug #10315]' a = [] def a.add(x) push(x); x; end def a.f(k:) k; end a.clear r = nil assert_warn(/duplicated/) {r = eval("a.f(k: a.add(1), k: a.add(2))")} assert_equal(2, r) assert_equal([1, 2], a, bug10315) a.clear r = nil assert_warn(/duplicated/) {r = eval("a.f({k: a.add(1), k: a.add(2)})")} assert_equal(2, r) assert_equal([1, 2], a, bug10315) end def test_keyword_self_reference bug9593 = '[ruby-core:61299] [Bug #9593]' o = Object.new assert_warn(/circular argument reference - var/) do o.instance_eval("def foo(var: defined?(var)) var end") end assert_equal(42, o.foo(var: 42)) assert_equal("local-variable", o.foo, bug9593) o = Object.new assert_warn(/circular argument reference - var/) do o.instance_eval("def foo(var: var) var end") end assert_nil(o.foo, bug9593) o = Object.new assert_warn(/circular argument reference - var/) do o.instance_eval("def foo(var: bar(var)) var end") end o = Object.new assert_warn(/circular argument reference - var/) do o.instance_eval("def foo(var: bar {var}) var end") end o = Object.new assert_warn("") do o.instance_eval("def foo(var: bar {|var| var}) var end") end o = Object.new assert_warn("") do o.instance_eval("def foo(var: def bar(var) var; end) var end") end o = Object.new assert_warn("") do o.instance_eval("proc {|var: 1| var}") end end def test_optional_self_reference bug9593 = '[ruby-core:61299] [Bug #9593]' o = Object.new assert_warn(/circular argument reference - var/) do o.instance_eval("def foo(var = defined?(var)) var end") end assert_equal(42, o.foo(42)) assert_equal("local-variable", o.foo, bug9593) o = Object.new assert_warn(/circular argument reference - var/) do o.instance_eval("def foo(var = var) var end") end assert_nil(o.foo, bug9593) o = Object.new assert_warn(/circular argument reference - var/) do o.instance_eval("def foo(var = bar(var)) var end") end o = Object.new assert_warn(/circular argument reference - var/) do o.instance_eval("def foo(var = bar {var}) var end") end o = Object.new assert_warn("") do o.instance_eval("def foo(var = bar {|var| var}) var end") end o = Object.new assert_warn("") do o.instance_eval("def foo(var = def bar(var) var; end) var end") end o = Object.new assert_warn("") do o.instance_eval("proc {|var = 1| var}") end end def test_warn_grouped_expression bug5214 = '[ruby-core:39050]' assert_warning("", bug5214) do assert_valid_syntax("foo \\\n(\n true)", "test", verbose: true) end end def test_warn_unreachable assert_warning("test:3: warning: statement not reached\n") do code = "loop do\n" "break\n" "foo\n" "end" assert_valid_syntax(code, "test", verbose: true) end end def test_warn_balanced warning = < (x, y) {}", __FILE__, feature6390) end def test_do_block_in_cmdarg_begin bug6419 = '[ruby-dev:45631]' assert_valid_syntax("p begin 1.times do 1 end end", __FILE__, bug6419) end def test_do_block_in_call_args bug9308 = '[ruby-core:59342] [Bug #9308]' assert_valid_syntax("bar def foo; self.each do end end", bug9308) end def test_reserved_method_no_args bug6403 = '[ruby-dev:45626]' assert_valid_syntax("def self; :foo; end", __FILE__, bug6403) end def test_unassignable gvar = global_variables %w[self nil true false __FILE__ __LINE__ __ENCODING__].each do |kwd| assert_raise(SyntaxError) {eval("#{kwd} = nil")} assert_equal(gvar, global_variables) end end Bug7559 = '[ruby-dev:46737]' def test_lineno_command_call_quote expected = __LINE__ + 1 actual = caller_lineno "a b c d e" assert_equal(expected, actual, "#{Bug7559}: ") end def test_lineno_after_heredoc bug7559 = '[ruby-dev:46737]' expected, _, actual = __LINE__, <