summaryrefslogtreecommitdiff
path: root/test/ruby/test_rubyoptions.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_rubyoptions.rb')
-rw-r--r--test/ruby/test_rubyoptions.rb230
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