diff options
Diffstat (limited to 'test/ruby/test_rubyoptions.rb')
| -rw-r--r-- | test/ruby/test_rubyoptions.rb | 230 |
1 files changed, 136 insertions, 94 deletions
diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb index 22663ed007..cd2dd5d3ff 100644 --- a/test/ruby/test_rubyoptions.rb +++ b/test/ruby/test_rubyoptions.rb @@ -5,21 +5,25 @@ require 'timeout' require 'tmpdir' require 'tempfile' require_relative '../lib/jit_support' +require_relative '../lib/parser_support' class TestRubyOptions < Test::Unit::TestCase - def self.rjit_enabled? = defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? - def self.yjit_enabled? = defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? - # Here we're defining our own RUBY_DESCRIPTION without "+PRISM". We do this # here so that the various tests that reference RUBY_DESCRIPTION don't have to # worry about it. The flag itself is tested in its own test. - RUBY_DESCRIPTION = ::RUBY_DESCRIPTION.sub(/\+PRISM /, '') + RUBY_DESCRIPTION = + if ParserSupport.prism_enabled_in_subprocess? + ::RUBY_DESCRIPTION + else + ::RUBY_DESCRIPTION.sub(/\+PRISM /, '') + end NO_JIT_DESCRIPTION = - if rjit_enabled? - RUBY_DESCRIPTION.sub(/\+RJIT /, '') - elsif yjit_enabled? - RUBY_DESCRIPTION.sub(/\+YJIT( (dev|dev_nodebug|stats))? /, '') + case + when JITSupport.yjit_enabled? + RUBY_DESCRIPTION.sub(/\+YJIT( \w+)? /, '') + when JITSupport.zjit_enabled? + RUBY_DESCRIPTION.sub(/\+ZJIT( \w+)? /, '') else RUBY_DESCRIPTION end @@ -43,10 +47,15 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err([], "", [], []) end + # This constant enforces the traditional 80x25 terminal size standard + TRADITIONAL_TERM_COLS = 80 # DO NOT MODIFY! + TRADITIONAL_TERM_ROWS = 25 # DO NOT MODIFY! + def test_usage + # This test checks if the output of `ruby -h` fits in 80x25 assert_in_out_err(%w(-h)) do |r, e| - assert_operator(r.size, :<=, 25) - longer = r[1..-1].select {|x| x.size >= 80} + assert_operator(r.size, :<=, TRADITIONAL_TERM_ROWS) + longer = r[1..-1].select {|x| x.size >= TRADITIONAL_TERM_COLS} assert_equal([], longer) assert_equal([], e) end @@ -112,7 +121,7 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%w(-We) + ['p $-W'], "", %w(2), []) assert_in_out_err(%w(-w -W0 -e) + ['p $-W'], "", %w(0), []) - categories = {deprecated: 1, experimental: 0, performance: 2} + categories = {deprecated: 1, experimental: 0, performance: 2, strict_unused_block: 3} assert_equal categories.keys.sort, Warning.categories.sort categories.each do |category, level| @@ -163,25 +172,14 @@ class TestRubyOptions < Test::Unit::TestCase /^jruby #{q[RUBY_ENGINE_VERSION]} \(#{q[RUBY_VERSION]}\).*? \[#{ q[RbConfig::CONFIG["host_os"]]}-#{q[RbConfig::CONFIG["host_cpu"]]}\]$/ else - /^ruby #{q[RUBY_VERSION]}(?:[p ]|dev|rc).*? \[#{q[RUBY_PLATFORM]}\]$/ + /^ruby #{q[RUBY_VERSION]}(?:[p ]|dev|rc).*? (\+PRISM )?\[#{q[RUBY_PLATFORM]}\]$/ end private_constant :VERSION_PATTERN - VERSION_PATTERN_WITH_RJIT = - case RUBY_ENGINE - when 'ruby' - /^ruby #{q[RUBY_VERSION]}(?:[p ]|dev|rc).*? \+RJIT (\+MN )?\[#{q[RUBY_PLATFORM]}\]$/ - else - VERSION_PATTERN - end - private_constant :VERSION_PATTERN_WITH_RJIT - def test_verbose assert_in_out_err([{'RUBY_YJIT_ENABLE' => nil}, "-vve", ""]) do |r, e| assert_match(VERSION_PATTERN, r[0]) - if self.class.rjit_enabled? && !JITSupport.rjit_force_enabled? - assert_equal(NO_JIT_DESCRIPTION, r[0]) - elsif self.class.yjit_enabled? && !JITSupport.yjit_force_enabled? + if (JITSupport.yjit_enabled? && !JITSupport.yjit_force_enabled?) || JITSupport.zjit_enabled? assert_equal(NO_JIT_DESCRIPTION, r[0]) else assert_equal(RUBY_DESCRIPTION, r[0]) @@ -206,15 +204,12 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%w(--enable all -e) + [""], "", [], []) assert_in_out_err(%w(--enable-all -e) + [""], "", [], []) assert_in_out_err(%w(--enable=all -e) + [""], "", [], []) - elsif JITSupport.rjit_supported? - # Avoid failing tests by RJIT warnings - assert_in_out_err(%w(--enable all --disable rjit -e) + [""], "", [], []) - assert_in_out_err(%w(--enable-all --disable-rjit -e) + [""], "", [], []) - assert_in_out_err(%w(--enable=all --disable=rjit -e) + [""], "", [], []) end assert_in_out_err(%w(--enable foobarbazqux -e) + [""], "", [], /unknown argument for --enable: 'foobarbazqux'/) assert_in_out_err(%w(--enable), "", [], /missing argument for --enable/) + assert_in_out_err(%w(-e) + ['p defined? Gem'], "", %w["constant"], [], gems: true) + assert_in_out_err(%w(-e) + ['p defined? Gem'], "", %w["constant"], [], gems: nil) end def test_disable @@ -224,14 +219,14 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%w(--disable foobarbazqux -e) + [""], "", [], /unknown argument for --disable: 'foobarbazqux'/) assert_in_out_err(%w(--disable), "", [], /missing argument for --disable/) - assert_in_out_err(%w(-e) + ['p defined? Gem'], "", ["nil"], []) + assert_in_out_err(%w(-e) + ['p defined? Gem'], "", ["nil"], [], gems: false) assert_in_out_err(%w(--disable-did_you_mean -e) + ['p defined? DidYouMean'], "", ["nil"], []) assert_in_out_err(%w(-e) + ['p defined? DidYouMean'], "", ["nil"], []) end def test_kanji assert_in_out_err(%w(-KU), "p '\u3042'") do |r, e| - assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8)) + assert_equal("\"\u3042\"", r.join('').force_encoding(Encoding::UTF_8)) end line = '-eputs"\xc2\xa1".encoding' env = {'RUBYOPT' => nil} @@ -252,7 +247,7 @@ class TestRubyOptions < Test::Unit::TestCase assert_match(VERSION_PATTERN, r[0]) if ENV['RUBY_YJIT_ENABLE'] == '1' assert_equal(NO_JIT_DESCRIPTION, r[0]) - elsif self.class.rjit_enabled? || self.class.yjit_enabled? # checking -D(M|Y)JIT_FORCE_ENABLE + elsif JITSupport.yjit_enabled? || JITSupport.zjit_enabled? # checking -DYJIT_FORCE_ENABLE assert_equal(EnvUtil.invoke_ruby(['-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0]) else assert_equal(RUBY_DESCRIPTION, r[0]) @@ -261,47 +256,19 @@ class TestRubyOptions < Test::Unit::TestCase end end - def test_rjit_disabled_version - return unless JITSupport.rjit_supported? - return if JITSupport.yjit_force_enabled? - - env = { 'RUBY_YJIT_ENABLE' => nil } # unset in children - [ - %w(--version --rjit --disable=rjit), - %w(--version --enable=rjit --disable=rjit), - %w(--version --enable-rjit --disable-rjit), - ].each do |args| - assert_in_out_err([env] + args) do |r, e| - assert_match(VERSION_PATTERN, r[0]) - assert_match(NO_JIT_DESCRIPTION, r[0]) - assert_equal([], e) - end - end - end - - def test_rjit_version - return unless JITSupport.rjit_supported? - return if JITSupport.yjit_force_enabled? + def test_enabled_gc + omit unless /linux|darwin/ =~ RUBY_PLATFORM - env = { 'RUBY_YJIT_ENABLE' => nil } # unset in children - [ - %w(--version --rjit), - %w(--version --enable=rjit), - %w(--version --enable-rjit), - ].each do |args| - assert_in_out_err([env] + args) do |r, e| - assert_match(VERSION_PATTERN_WITH_RJIT, r[0]) - if JITSupport.rjit_force_enabled? - assert_equal(RUBY_DESCRIPTION, r[0]) - else - assert_equal(EnvUtil.invoke_ruby([env, '--rjit', '-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0]) - end - assert_equal([], e) - end + if RbConfig::CONFIG['modular_gc_dir'].length > 0 + assert_match(/\+GC/, RUBY_DESCRIPTION) + else + assert_no_match(/\+GC/, RUBY_DESCRIPTION) end end def test_parser_flag + omit if ENV["RUBYOPT"]&.include?("--parser=") + assert_in_out_err(%w(--parser=prism -e) + ["puts :hi"], "", %w(hi), []) assert_in_out_err(%w(--parser=prism --dump=parsetree -e _=:hi), "", /"hi"/, []) @@ -356,12 +323,25 @@ class TestRubyOptions < Test::Unit::TestCase d = Dir.tmpdir assert_in_out_err(["-C", d, "-e", "puts Dir.pwd"]) do |r, e| - assert_file.identical?(r.join, d) + assert_file.identical?(r.join(''), d) assert_equal([], e) end + + Dir.mktmpdir(nil, d) do |base| + # "test" in Japanese and N'Ko + test = base + "/\u{30c6 30b9 30c8}_\u{7e1 7ca 7dd 7cc 7df 7cd 7eb}" + Dir.mkdir(test) + assert_in_out_err(["-C", base, "-C", File.basename(test), "-e", "puts Dir.pwd"]) do |r, e| + assert_file.identical?(r.join(''), test) + assert_equal([], e) + end + Dir.rmdir(test) + end end def test_yydebug + omit if ParserSupport.prism_enabled_in_subprocess? + assert_in_out_err(["-ye", ""]) do |r, e| assert_not_equal([], r) assert_equal([], e) @@ -387,16 +367,16 @@ class TestRubyOptions < Test::Unit::TestCase def test_syntax_check assert_in_out_err(%w(-cw -e a=1+1 -e !a), "", ["Syntax OK"], []) - assert_in_out_err(%w(-cw -e break), "", [], ["-e:1: Invalid break", :*]) - assert_in_out_err(%w(-cw -e next), "", [], ["-e:1: Invalid next", :*]) - assert_in_out_err(%w(-cw -e redo), "", [], ["-e:1: Invalid redo", :*]) - assert_in_out_err(%w(-cw -e retry), "", [], ["-e:1: Invalid retry", :*]) - assert_in_out_err(%w(-cw -e yield), "", [], ["-e:1: Invalid yield", :*]) - assert_in_out_err(%w(-cw -e begin -e break -e end), "", [], ["-e:2: Invalid break", :*]) - assert_in_out_err(%w(-cw -e begin -e next -e end), "", [], ["-e:2: Invalid next", :*]) - assert_in_out_err(%w(-cw -e begin -e redo -e end), "", [], ["-e:2: Invalid redo", :*]) - assert_in_out_err(%w(-cw -e begin -e retry -e end), "", [], ["-e:2: Invalid retry", :*]) - assert_in_out_err(%w(-cw -e begin -e yield -e end), "", [], ["-e:2: Invalid yield", :*]) + assert_in_out_err(%w(-cw -e break), "", [], [:*, /(-e:1:|~) Invalid break/, :*]) + assert_in_out_err(%w(-cw -e next), "", [], [:*, /(-e:1:|~) Invalid next/, :*]) + assert_in_out_err(%w(-cw -e redo), "", [], [:*, /(-e:1:|~) Invalid redo/, :*]) + assert_in_out_err(%w(-cw -e retry), "", [], [:*, /(-e:1:|~) Invalid retry/, :*]) + assert_in_out_err(%w(-cw -e yield), "", [], [:*, /(-e:1:|~) Invalid yield/, :*]) + assert_in_out_err(%w(-cw -e begin -e break -e end), "", [], [:*, /(-e:2:|~) Invalid break/, :*]) + assert_in_out_err(%w(-cw -e begin -e next -e end), "", [], [:*, /(-e:2:|~) Invalid next/, :*]) + assert_in_out_err(%w(-cw -e begin -e redo -e end), "", [], [:*, /(-e:2:|~) Invalid redo/, :*]) + assert_in_out_err(%w(-cw -e begin -e retry -e end), "", [], [:*, /(-e:2:|~) Invalid retry/, :*]) + assert_in_out_err(%w(-cw -e begin -e yield -e end), "", [], [:*, /(-e:2:|~) Invalid yield/, :*]) assert_in_out_err(%w(-cw -e !defined?(break)), "", ["Syntax OK"], []) assert_in_out_err(%w(-cw -e !defined?(next)), "", ["Syntax OK"], []) assert_in_out_err(%w(-cw -e !defined?(redo)), "", ["Syntax OK"], []) @@ -412,11 +392,15 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%W(-\r -e) + [""], "", [], []) - assert_in_out_err(%W(-\rx), "", [], /invalid option -[\r\n] \(-h will show valid options\) \(RuntimeError\)/) + assert_in_out_err(%W(-\rx), "", [], /invalid option -\\r \(-h will show valid options\) \(RuntimeError\)/) - assert_in_out_err(%W(-\x01), "", [], /invalid option -\x01 \(-h will show valid options\) \(RuntimeError\)/) + assert_in_out_err(%W(-\x01), "", [], /invalid option -\\x01 \(-h will show valid options\) \(RuntimeError\)/) assert_in_out_err(%w(-Z), "", [], /invalid option -Z \(-h will show valid options\) \(RuntimeError\)/) + + assert_in_out_err(%W(-\u{1f608}), "", [], + /invalid option -(\\xf0|\u{1f608}) \(-h will show valid options\) \(RuntimeError\)/, + encoding: Encoding::UTF_8) end def test_rubyopt @@ -544,6 +528,8 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%w(- -#=foo), "#!ruby -s\n", [], /invalid name for global variable - -# \(NameError\)/) + + assert_in_out_err(['-s', '-e', 'GC.start; p $DEBUG', '--', '-DEBUG=x'], "", ['"x"']) end def test_option_missing_argument @@ -810,14 +796,22 @@ class TestRubyOptions < Test::Unit::TestCase unless /mswin|mingw/ =~ RUBY_PLATFORM opts[:rlimit_core] = 0 end + opts[:failed] = proc do |status, message = "", out = ""| + if (sig = status.termsig) && Signal.list["SEGV"] == sig + out = "" + end + Test::Unit::CoreAssertions::FailDesc[status, message] + end ExecOptions = opts.freeze + # The regexp list that should match the entire stderr output. + # see assert_pattern_list ExpectedStderrList = [ %r( - -e:(?:1:)?\s\[BUG\]\sSegmentation\sfault.*\n + (?:-e:(?:1:)?\s)?\[BUG\]\sSegmentation\sfault.*\n )x, %r( - #{ Regexp.quote((TestRubyOptions.rjit_enabled? && !JITSupport.rjit_force_enabled?) ? NO_JIT_DESCRIPTION : RUBY_DESCRIPTION) }\n\n + #{ Regexp.quote(RUBY_DESCRIPTION) }\n\n )x, %r( (?:--\s(?:.+\n)*\n)? @@ -860,15 +854,21 @@ class TestRubyOptions < Test::Unit::TestCase # We want YJIT to be enabled in the subprocess if it's enabled for us # so that the Ruby description matches. env = Hash === args.first ? args.shift : {} - args.unshift("--yjit") if self.class.yjit_enabled? + args.unshift("--yjit") if JITSupport.yjit_enabled? + args.unshift("--zjit") if JITSupport.zjit_enabled? env.update({'RUBY_ON_BUG' => nil}) + env['RUBY_CRASH_REPORT'] ||= nil # default to not passing down parent setting # ASAN registers a segv handler which prints out "AddressSanitizer: DEADLYSIGNAL" when # catching sigsegv; we don't expect that output, so suppress it. - env.update({'ASAN_OPTIONS' => 'handle_segv=0'}) + env.update({'ASAN_OPTIONS' => 'handle_segv=0', 'LSAN_OPTIONS' => 'handle_segv=0'}) args.unshift(env) test_stdin = "" - tests = [//, list] unless block + if !block + tests = [//, list, message] + elsif message + tests = [[], [], message] + end assert_in_out_err(args, test_stdin, *tests, encoding: "ASCII-8BIT", **SEGVTest::ExecOptions, **opt, &block) @@ -881,13 +881,12 @@ class TestRubyOptions < Test::Unit::TestCase def test_segv_loaded_features bug7402 = '[ruby-core:49573]' - status = assert_segv(['-e', "END {#{SEGVTest::KILL_SELF}}", - '-e', 'class Bogus; def to_str; exit true; end; end', - '-e', '$".clear', - '-e', '$".unshift Bogus.new', - '-e', '(p $"; abort) unless $".size == 1', - ]) - assert_not_predicate(status, :success?, "segv but success #{bug7402}") + assert_segv(['-e', "END {#{SEGVTest::KILL_SELF}}", + '-e', 'class Bogus; def to_str; exit true; end; end', + '-e', '$".clear', + '-e', '$".unshift Bogus.new', + '-e', '(p $"; abort) unless $".size == 1', + ], bug7402, success: false) end def test_segv_setproctitle @@ -953,6 +952,27 @@ class TestRubyOptions < Test::Unit::TestCase end end + def test_crash_report_pipe_script + omit "only runs on Linux" unless RUBY_PLATFORM.include?("linux") + + Tempfile.create(["script", ".sh"]) do |script| + Tempfile.create("crash_report") do |crash_report| + script.write(<<~BASH) + #!/usr/bin/env bash + + cat > #{crash_report.path} + BASH + script.close + + FileUtils.chmod("+x", script) + + assert_crash_report("| #{script.path}") do + assert_include(File.read(crash_report.path), "[BUG] Segmentation fault at") + end + end + end + end + def test_DATA Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t| t.puts "puts DATA.read.inspect" @@ -999,7 +1019,7 @@ class TestRubyOptions < Test::Unit::TestCase pid = spawn(EnvUtil.rubybin, :in => s, :out => w) w.close assert_nothing_raised('[ruby-dev:37798]') do - result = EnvUtil.timeout(3) {r.read} + result = EnvUtil.timeout(10) {r.read} end Process.wait pid } @@ -1169,6 +1189,8 @@ class TestRubyOptions < Test::Unit::TestCase end def test_dump_parsetree_error_tolerant + omit if ParserSupport.prism_enabled_in_subprocess? + assert_in_out_err(['--dump=parse', '-e', 'begin'], "", [], /unexpected end-of-input/, success: false) assert_in_out_err(['--dump=parse', '--dump=+error_tolerant', '-e', 'begin'], @@ -1233,6 +1255,16 @@ class TestRubyOptions < Test::Unit::TestCase end end + def test_frozen_string_literal_debug_chilled_strings + code = <<~RUBY + "foo" << "bar" + RUBY + assert_in_out_err(["-W:deprecated"], code, [], ["-:1: warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information)"]) + assert_in_out_err(["-W:deprecated", "--debug-frozen-string-literal"], code, [], ["-:1: warning: literal string will be frozen in the future", "-:1: info: the string was created here"]) + assert_in_out_err(["-W:deprecated", "--disable-frozen-string-literal", "--debug-frozen-string-literal"], code, [], []) + assert_in_out_err(["-W:deprecated", "--enable-frozen-string-literal", "--debug-frozen-string-literal"], code, [], ["-:1:in '<main>': can't modify frozen String: \"foo\", created at -:1 (FrozenError)"]) + end + def test___dir__encoding lang = {"LC_ALL"=>ENV["LC_ALL"]||ENV["LANG"]} with_tmpchdir do @@ -1281,4 +1313,14 @@ class TestRubyOptions < Test::Unit::TestCase assert_ruby_status([env, "-e;"]) assert_in_out_err([env, "-W"], "", [], /Free at exit is experimental and may be unstable/) end + + def test_toplevel_ruby + assert_instance_of Module, ::Ruby + end + + def test_ruby_patchlevel + # We stopped bumping RUBY_PATCHLEVEL at Ruby 4.0.0. + # Released versions have RUBY_PATCHLEVEL 0, and un-released versions have -1. + assert_include [-1, 0], RUBY_PATCHLEVEL + end end |
