diff options
Diffstat (limited to 'test/ruby/test_require.rb')
| -rw-r--r-- | test/ruby/test_require.rb | 574 |
1 files changed, 471 insertions, 103 deletions
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb index 3b7f6a7977..0067a49700 100644 --- a/test/ruby/test_require.rb +++ b/test/ruby/test_require.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: false require 'test/unit' require 'tempfile' @@ -5,11 +6,27 @@ require 'tmpdir' class TestRequire < Test::Unit::TestCase def test_load_error_path - filename = "should_not_exist" - error = assert_raise(LoadError) do - require filename - end - assert_equal filename, error.path + Tempfile.create(["should_not_exist", ".rb"]) {|t| + filename = t.path + t.close + File.unlink(filename) + + error = assert_raise(LoadError) do + require filename + end + assert_equal filename, error.path + + # with --disable=gems + assert_separately(["-", filename], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + filename = ARGV[0] + path = Struct.new(:to_path).new(filename) + error = assert_raise(LoadError) do + require path + end + assert_equal filename, error.path + end; + } end def test_require_invalid_shared_object @@ -17,22 +34,24 @@ class TestRequire < Test::Unit::TestCase t.puts "dummy" t.close - assert_separately([], <<-INPUT) + assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}") + begin; $:.replace([IO::NULL]) assert_raise(LoadError) do require \"#{ t.path }\" end - INPUT + end; } end def test_require_too_long_filename - assert_separately(["RUBYOPT"=>nil], <<-INPUT) + assert_separately(["RUBYOPT"=>nil], "#{<<~"begin;"}\n#{<<~"end;"}") + begin; $:.replace([IO::NULL]) assert_raise(LoadError) do require '#{ "foo/" * 10000 }foo' end - INPUT + end; begin assert_in_out_err(["-S", "-w", "foo/" * 1024 + "foo"], "") do |r, e| @@ -49,7 +68,8 @@ class TestRequire < Test::Unit::TestCase def test_require_nonascii bug3758 = '[ruby-core:31915]' ["\u{221e}", "\x82\xa0".force_encoding("cp932")].each do |path| - assert_raise_with_message(LoadError, /#{path}\z/, bug3758) {require path} + e = assert_raise(LoadError, bug3758) {require path} + assert_operator(e.message, :end_with?, path, bug3758) end end @@ -84,19 +104,30 @@ class TestRequire < Test::Unit::TestCase end end - def assert_require_nonascii_path(encoding, bug) + def prepare_require_path(dir, encoding) + require 'enc/trans/single_byte' Dir.mktmpdir {|tmp| - dir = "\u3042" * 5 begin require_path = File.join(tmp, dir, 'foo.rb').encode(encoding) rescue - skip "cannot convert path encoding to #{encoding}" + omit "cannot convert path encoding to #{encoding}" end Dir.mkdir(File.dirname(require_path)) open(require_path, "wb") {|f| f.puts '$:.push __FILE__'} begin load_path = $:.dup features = $".dup + yield require_path + ensure + $:.replace(load_path) + $".replace(features) + end + } + end + + def assert_require_nonascii_path(encoding, bug) + prepare_require_path("\u3042" * 5, encoding) {|require_path| + begin # leave paths for require encoding objects bug = "#{bug} require #{encoding} path" require_path = "#{require_path}" @@ -106,9 +137,6 @@ class TestRequire < Test::Unit::TestCase assert_equal(self.class.ospath_encoding(require_path), $:.last.encoding, '[Bug #8753]') assert(!require(require_path), bug) } - ensure - $:.replace(load_path) - $".replace(features) end } end @@ -159,13 +187,20 @@ class TestRequire < Test::Unit::TestCase end def test_require_with_unc - ruby = File.expand_path(EnvUtil.rubybin).sub(/\A(\w):/, '//127.0.0.1/\1$/') - skip "local drive #$1: is not shared" unless File.exist?(ruby) - pid = nil - assert_nothing_raised {pid = spawn(ruby, "-rabbrev", "-e0")} - ret, status = Process.wait2(pid) - assert_equal(pid, ret) - assert_predicate(status, :success?) + Tempfile.create(["test_ruby_test_require", ".rb"]) {|t| + t.puts "puts __FILE__" + t.close + + path = File.expand_path(t.path).sub(/\A(\w):/, '//127.0.0.1/\1$') + omit "local drive #$1: is not shared" unless File.exist?(path) + args = ['--disable-gems', "-I#{File.dirname(path)}"] + assert_in_out_err(args, "#{<<~"END;"}", [path], []) + begin + require '#{File.basename(path)}' + rescue Errno::EPERM + end + END; + } end if /mswin|mingw/ =~ RUBY_PLATFORM def test_require_twice @@ -174,13 +209,43 @@ class TestRequire < Test::Unit::TestCase File.write(req, "p :ok\n") assert_file.exist?(req) req[/.rb$/i] = "" - assert_in_out_err(['--disable-gems'], <<-INPUT, %w(:ok), []) + assert_in_out_err([], <<-INPUT, %w(:ok), []) require "#{req}" require "#{req}" INPUT end end + def assert_syntax_error_backtrace + loaded_features = $LOADED_FEATURES.dup + Dir.mktmpdir do |tmp| + req = File.join(tmp, "test.rb") + File.write(req, ",\n") + e = assert_raise_with_message(SyntaxError, /unexpected/) { + yield req + } + assert_not_nil(bt = e.backtrace, "no backtrace") + assert_not_empty(bt.find_all {|b| b.start_with? __FILE__}, proc {bt.inspect}) + end + ensure + $LOADED_FEATURES.replace loaded_features + end + + def test_require_syntax_error + assert_syntax_error_backtrace {|req| require req} + end + + def test_require_syntax_error_rescued + assert_syntax_error_backtrace do |req| + assert_raise_with_message(SyntaxError, /unexpected/) {require req} + require req + end + end + + def test_load_syntax_error + assert_syntax_error_backtrace {|req| load req} + end + def test_define_class begin require "socket" @@ -228,7 +293,7 @@ class TestRequire < Test::Unit::TestCase assert_separately([], <<-INPUT) module Zlib; end class Zlib::Error; end - assert_raise(NameError) do + assert_raise(TypeError) do require 'zlib' end INPUT @@ -292,6 +357,39 @@ class TestRequire < Test::Unit::TestCase } end + def test_require_in_wrapped_load + Dir.mktmpdir do |tmp| + File.write("#{tmp}/1.rb", "require_relative '2'\n") + File.write("#{tmp}/2.rb", "class Foo\n""end\n") + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + path = ""#{tmp.dump}"/1.rb" + begin; + load path, true + assert_instance_of(Class, Foo) + end; + end + end + + def test_public_in_wrapped_load + Tempfile.create(["test_public_in_wrapped_load", ".rb"]) do |t| + t.puts "def foo; end", "public :foo" + t.close + assert_warning(/main\.public/) do + assert load(t.path, true) + end + end + end + + def test_private_in_wrapped_load + Tempfile.create(["test_private_in_wrapped_load", ".rb"]) do |t| + t.puts "def foo; end", "private :foo" + t.close + assert_warning(/main\.private/) do + assert load(t.path, true) + end + end + end + def test_load_scope bug1982 = '[ruby-core:25039] [Bug #1982]' Tempfile.create(["test_ruby_test_require", ".rb"]) {|t| @@ -307,19 +405,51 @@ class TestRequire < Test::Unit::TestCase } end + def test_load_into_module + Tempfile.create(["test_ruby_test_require", ".rb"]) {|t| + t.puts "def b; 1 end" + t.puts "class Foo" + t.puts " def c; 2 end" + t.puts "end" + t.close + + m = Module.new + load(t.path, m) + assert_equal([:b], m.private_instance_methods(false)) + c = Class.new do + include m + public :b + end + assert_equal(1, c.new.b) + assert_equal(2, m::Foo.new.c) + } + end + + def test_load_wrap_nil + Dir.mktmpdir do |tmp| + File.write("#{tmp}/1.rb", "class LoadWrapNil; end\n") + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + path = ""#{tmp.dump}"/1.rb" + begin; + load path, nil + assert_instance_of(Class, LoadWrapNil) + end; + end + end + def test_load_ospath bug = '[ruby-list:49994] path in ospath' base = "test_load\u{3042 3044 3046 3048 304a}".encode(Encoding::Windows_31J) path = nil - Tempfile.create([base, ".rb"]) do |t| - path = t.path - + Dir.mktmpdir do |dir| + path = File.join(dir, base+".rb") assert_raise_with_message(LoadError, /#{base}/) { - load(File.join(File.dirname(path), base)) + load(File.join(dir, base)) } - t.puts "warn 'ok'" - t.close + File.open(path, "w+b") do |t| + t.puts "warn 'ok'" + end assert_include(path, base) assert_warn("ok\n", bug) { assert_nothing_raised(LoadError, bug) { @@ -329,47 +459,10 @@ class TestRequire < Test::Unit::TestCase end end - def test_tainted_loadpath - Tempfile.create(["test_ruby_test_require", ".rb"]) {|t| - abs_dir, file = File.split(t.path) - abs_dir = File.expand_path(abs_dir).untaint - - assert_separately([], <<-INPUT) - abs_dir = "#{ abs_dir }" - $: << abs_dir - assert_nothing_raised {require "#{ file }"} - INPUT - - assert_separately([], <<-INPUT) - abs_dir = "#{ abs_dir }" - $: << abs_dir.taint - assert_nothing_raised {require "#{ file }"} - INPUT - - assert_separately([], <<-INPUT) - abs_dir = "#{ abs_dir }" - $: << abs_dir.taint - $SAFE = 1 - assert_raise(SecurityError) {require "#{ file }"} - INPUT - - assert_separately([], <<-INPUT) - abs_dir = "#{ abs_dir }" - $: << abs_dir.taint - $SAFE = 1 - assert_raise(SecurityError) {require "#{ file }"} - INPUT - - assert_separately([], <<-INPUT) - abs_dir = "#{ abs_dir }" - $: << abs_dir << 'elsewhere'.taint - assert_nothing_raised {require "#{ file }"} - INPUT - } - end - def test_relative load_path = $:.dup + loaded_featrures = $LOADED_FEATURES.dup + $:.delete(".") Dir.mktmpdir do |tmp| Dir.chdir(tmp) do @@ -389,6 +482,7 @@ class TestRequire < Test::Unit::TestCase end ensure $:.replace(load_path) if load_path + $LOADED_FEATURES.replace loaded_featrures end def test_relative_symlink @@ -403,8 +497,34 @@ class TestRequire < Test::Unit::TestCase File.symlink("../a/tst.rb", "b/tst.rb") result = IO.popen([EnvUtil.rubybin, "b/tst.rb"], &:read) assert_equal("a/lib.rb\n", result, "[ruby-dev:40040]") - rescue NotImplementedError - skip "File.symlink is not implemented" + rescue NotImplementedError, Errno::EACCES + omit "File.symlink is not implemented" + end + } + } + end + + def test_relative_symlink_realpath + Dir.mktmpdir {|tmp| + Dir.chdir(tmp) { + Dir.mkdir "a" + File.open("a/a.rb", "w") {|f| f.puts 'require_relative "b"' } + File.open("a/b.rb", "w") {|f| f.puts '$t += 1' } + Dir.mkdir "b" + File.binwrite("c.rb", <<~RUBY) + $t = 0 + $:.unshift(File.expand_path('../b', __FILE__)) + require "b" + require "a" + print $t + RUBY + begin + File.symlink("../a/a.rb", "b/a.rb") + File.symlink("../a/b.rb", "b/b.rb") + result = IO.popen([EnvUtil.rubybin, "c.rb"], &:read) + assert_equal("1", result, "bug17885 [ruby-core:104010]") + rescue NotImplementedError, Errno::EACCES + omit "File.symlink is not implemented" end } } @@ -412,7 +532,7 @@ class TestRequire < Test::Unit::TestCase def test_frozen_loaded_features bug3756 = '[ruby-core:31913]' - assert_in_out_err(['-e', '$LOADED_FEATURES.freeze; require "ostruct"'], "", + assert_in_out_err(['-e', '$LOADED_FEATURES.freeze; require "erb"'], "", [], /\$LOADED_FEATURES is frozen; cannot append feature \(RuntimeError\)$/, bug3756) end @@ -424,7 +544,8 @@ class TestRequire < Test::Unit::TestCase verbose = $VERBOSE Tempfile.create(%w"bug5754 .rb") {|tmp| path = tmp.path - tmp.print %{\ + tmp.print "#{<<~"begin;"}\n#{<<~"end;"}" + begin; th = Thread.current t = th[:t] scratch = th[:scratch] @@ -436,7 +557,7 @@ class TestRequire < Test::Unit::TestCase else scratch << :post end - } + end; tmp.close class << (output = "") @@ -453,7 +574,7 @@ class TestRequire < Test::Unit::TestCase t1 = Thread.new do Thread.pass until start begin - require(path) + Kernel.send(:require, path) rescue RuntimeError end @@ -462,7 +583,7 @@ class TestRequire < Test::Unit::TestCase t2 = Thread.new do Thread.pass until scratch[0] - t2_res = require(path) + t2_res = Kernel.send(:require, path) end t1[:scratch] = t2[:scratch] = scratch @@ -479,9 +600,6 @@ class TestRequire < Test::Unit::TestCase assert_equal(true, (t1_res ^ t2_res), bug5754 + " t1:#{t1_res} t2:#{t2_res}") assert_equal([:pre, :post], scratch, bug5754) - - assert_match(/circular require/, output) - assert_match(/in #{__method__}'$/o, output) } ensure $VERBOSE = verbose @@ -506,6 +624,28 @@ class TestRequire < Test::Unit::TestCase $".replace(features) end + def test_default_loaded_features_encoding + Dir.mktmpdir {|tmp| + Dir.mkdir("#{tmp}/1") + Dir.mkdir("#{tmp}/2") + File.write("#{tmp}/1/bug18191-1.rb", "") + File.write("#{tmp}/2/bug18191-2.rb", "") + assert_separately(%W[-Eutf-8 -I#{tmp}/1 -], "#{<<~"begin;"}\n#{<<~'end;'}") + tmp = #{tmp.dump}"/2" + begin; + $:.unshift(tmp) + require "bug18191-1" + require "bug18191-2" + encs = [Encoding::US_ASCII, Encoding.find("filesystem")] + message = -> { + require "pp" + {filesystem: encs[1], **$".group_by(&:encoding)}.pretty_inspect + } + assert($".all? {|n| encs.include?(n.encoding)}, message) + end; + } + end + def test_require_changed_current_dir bug7158 = '[ruby-core:47970]' Dir.mktmpdir {|tmp| @@ -516,7 +656,8 @@ class TestRequire < Test::Unit::TestCase open(File.join("b", "bar.rb"), "w") {|f| f.puts "p :ok" } - assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158) + assert_in_out_err([], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) + begin; $:.replace([IO::NULL]) $: << "." Dir.chdir("a") @@ -525,7 +666,7 @@ class TestRequire < Test::Unit::TestCase p :ng unless require "bar" Dir.chdir("..") p :ng if require "b/bar" - INPUT + end; } } end @@ -535,7 +676,8 @@ class TestRequire < Test::Unit::TestCase Dir.mktmpdir {|tmp| Dir.chdir(tmp) { open("foo.rb", "w") {} - assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158) + assert_in_out_err([], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) + begin; $:.replace([IO::NULL]) a = Object.new def a.to_str @@ -545,7 +687,7 @@ class TestRequire < Test::Unit::TestCase require "foo" last_path = $:.pop p :ok if last_path == a && last_path.class == Object - INPUT + end; } } end @@ -557,14 +699,15 @@ class TestRequire < Test::Unit::TestCase open("foo.rb", "w") {} Dir.mkdir("a") open(File.join("a", "bar.rb"), "w") {} - assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7158) + assert_in_out_err([], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) + begin; $:.replace([IO::NULL]) $: << '~' ENV['HOME'] = "#{tmp}" require "foo" ENV['HOME'] = "#{tmp}/a" p :ok if require "bar" - INPUT + end; } } end @@ -574,7 +717,8 @@ class TestRequire < Test::Unit::TestCase Dir.mktmpdir {|tmp| Dir.chdir(tmp) { open("foo.rb", "w") {} - assert_in_out_err(["RUBYOPT"=>nil], <<-INPUT, %w(:ok), [], bug7158) + assert_in_out_err([{"RUBYOPT"=>nil}], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) + begin; $:.replace([IO::NULL]) a = Object.new def a.to_path @@ -584,13 +728,14 @@ class TestRequire < Test::Unit::TestCase begin require "foo" p [:ng, $LOAD_PATH, ENV['RUBYLIB']] - rescue LoadError + rescue LoadError => e + raise unless e.path == "foo" end def a.to_path "#{tmp}" end p :ok if require "foo" - INPUT + end; } } end @@ -600,7 +745,8 @@ class TestRequire < Test::Unit::TestCase Dir.mktmpdir {|tmp| Dir.chdir(tmp) { open("foo.rb", "w") {} - assert_in_out_err(["RUBYOPT"=>nil], <<-INPUT, %w(:ok), [], bug7158) + assert_in_out_err([{"RUBYOPT"=>nil}], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7158) + begin; $:.replace([IO::NULL]) a = Object.new def a.to_str @@ -610,13 +756,14 @@ class TestRequire < Test::Unit::TestCase begin require "foo" p [:ng, $LOAD_PATH, ENV['RUBYLIB']] - rescue LoadError + rescue LoadError => e + raise unless e.path == "foo" end def a.to_str "#{tmp}" end p :ok if require "foo" - INPUT + end; } } end @@ -628,7 +775,8 @@ class TestRequire < Test::Unit::TestCase open("foo.rb", "w") {} Dir.mkdir("a") open(File.join("a", "bar.rb"), "w") {} - assert_in_out_err([], <<-INPUT, %w(:ok), [], bug7383) + assert_in_out_err([], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7383) + begin; $:.replace([IO::NULL]) $:.#{add} "#{tmp}" $:.#{add} "#{tmp}/a" @@ -637,10 +785,14 @@ class TestRequire < Test::Unit::TestCase # Expanded load path cache should be rebuilt. begin require "bar" - rescue LoadError - p :ok + rescue LoadError => e + if e.path == "bar" + p :ok + else + raise + end end - INPUT + end; } } end @@ -658,10 +810,11 @@ class TestRequire < Test::Unit::TestCase Dir.mktmpdir {|tmp| Dir.chdir(tmp) { open("bar.rb", "w") {|f| f.puts 'TOPLEVEL_BINDING.eval("lib = 2")' } - assert_in_out_err(%w[-r./bar.rb], <<-INPUT, %w([:lib] 2), [], bug7536) + assert_in_out_err(%w[-r./bar.rb], "#{<<~"begin;"}\n#{<<~"end;"}", %w([:lib] 2), [], bug7536) + begin; puts TOPLEVEL_BINDING.eval("local_variables").inspect puts TOPLEVEL_BINDING.eval("lib").inspect - INPUT + end; } } end @@ -670,21 +823,236 @@ class TestRequire < Test::Unit::TestCase bug7530 = '[ruby-core:50645]' Tempfile.create(%w'bug-7530- .rb') {|script| script.close - assert_in_out_err([{"RUBYOPT" => nil}, "-", script.path], <<-INPUT, %w(:ok), [], bug7530) + assert_in_out_err([{"RUBYOPT" => nil}, "-", script.path], "#{<<~"begin;"}\n#{<<~"end;"}", %w(:ok), [], bug7530, timeout: 60) + begin; PATH = ARGV.shift - THREADS = 2 - ITERATIONS_PER_THREAD = 1000 + THREADS = 30 + ITERATIONS_PER_THREAD = 300 THREADS.times.map { Thread.new do ITERATIONS_PER_THREAD.times do require PATH - $".pop + $".delete_if {|p| Regexp.new(PATH) =~ p} end end }.each(&:join) p :ok - INPUT + end; + } + + # [Bug #21567] + assert_ruby_status(%w[-rtempfile], "#{<<~"begin;"}\n#{<<~"end;"}") + begin; + class MyString + def initialize(path) + @path = path + end + + def to_str + $LOADED_FEATURES.clear + @path + end + + def to_path = @path + end + + FILES = [] + + def create_ruby_file + file = Tempfile.open(["test", ".rb"]) + FILES << file + file.path + end + + require MyString.new(create_ruby_file) + $LOADED_FEATURES.unshift(create_ruby_file) + $LOADED_FEATURES << MyString.new(create_ruby_file) + require create_ruby_file + end; + end + + def test_loading_fifo_threading_raise + Tempfile.create(%w'fifo .rb') {|f| + f.close + File.unlink(f.path) + File.mkfifo(f.path) + assert_separately(["-", f.path], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10) + begin; + th = Thread.current + Thread.start {begin sleep(0.001) end until th.stop?; th.raise(IOError)} + assert_raise(IOError) do + load(ARGV[0]) + end + end; + } + end if File.respond_to?(:mkfifo) + + def test_loading_fifo_threading_success + omit "[Bug #18613]" if /freebsd/=~ RUBY_PLATFORM + + Tempfile.create(%w'fifo .rb') {|f| + f.close + File.unlink(f.path) + File.mkfifo(f.path) + + assert_separately(["-", f.path], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10) + begin; + path = ARGV[0] + th = Thread.current + $ok = false + Thread.start { + begin + sleep(0.001) + end until th.stop? + open(path, File::WRONLY | File::NONBLOCK) {|fifo_w| + fifo_w.print "$ok = true\n__END__\n" # ensure finishing + } + } + + load(path) + assert($ok) + end; + } + end if File.respond_to?(:mkfifo) + + def test_loading_fifo_fd_leak + omit if RUBY_PLATFORM =~ /android/ # https://rubyci.org/logs/rubyci.s3.amazonaws.com/android29-x86_64/ruby-master/log/20200419T124100Z.fail.html.gz + + Tempfile.create(%w'fifo .rb') {|f| + f.close + File.unlink(f.path) + File.mkfifo(f.path) + assert_separately(["-", f.path], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 3) + begin; + Process.setrlimit(Process::RLIMIT_NOFILE, 50) + th = Thread.current + 100.times do |i| + Thread.start {begin sleep(0.001) end until th.stop?; th.raise(IOError)} + assert_raise(IOError, "\#{i} time") do + begin + tap {tap {tap {load(ARGV[0])}}} + rescue LoadError + GC.start + retry + end + end + end + end; } + end if File.respond_to?(:mkfifo) and defined?(Process::RLIMIT_NOFILE) + + def test_throw_while_loading + Tempfile.create(%w'bug-11404 .rb') do |f| + f.puts 'sleep' + f.close + + assert_separately(["-", f.path], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + path = ARGV[0] + class Error < RuntimeError + def exception(*) + begin + throw :blah + rescue UncaughtThrowError + end + self + end + end + + assert_throw(:blah) do + x = Thread.current + Thread.start { + sleep 0.00001 + x.raise Error.new + } + load path + end + end; + end + end + + def test_symlink_load_path + Dir.mktmpdir {|tmp| + Dir.mkdir(File.join(tmp, "real")) + begin + File.symlink "real", File.join(tmp, "symlink") + rescue NotImplementedError, Errno::EACCES + omit "File.symlink is not implemented" + end + File.write(File.join(tmp, "real/test_symlink_load_path.rb"), "print __FILE__") + result = IO.popen([EnvUtil.rubybin, "-I#{tmp}/symlink", "-e", "require 'test_symlink_load_path.rb'"], &:read) + assert_operator(result, :end_with?, "/real/test_symlink_load_path.rb") + } + end + + def test_provide_in_required_file + paths, loaded = $:.dup, $".dup + Dir.mktmpdir do |tmp| + provide = File.realdirpath("provide.rb", tmp) + File.write(File.join(tmp, "target.rb"), "raise __FILE__\n") + File.write(provide, '$" << '"'target.rb'\n") + $:.replace([tmp]) + assert(require("provide")) + assert(!require("target")) + assert_equal($".pop, provide) + assert_equal($".pop, "target.rb") + end + ensure + $:.replace(paths) + $".replace(loaded) + end + + if defined?($LOAD_PATH.resolve_feature_path) + def test_resolve_feature_path + paths, loaded = $:.dup, $".dup + Dir.mktmpdir do |tmp| + Tempfile.create(%w[feature .rb], tmp) do |file| + file.close + path = File.realpath(file.path) + dir, base = File.split(path) + $:.unshift(dir) + assert_equal([:rb, path], $LOAD_PATH.resolve_feature_path(base)) + $".push(path) + assert_equal([:rb, path], $LOAD_PATH.resolve_feature_path(base)) + end + end + ensure + $:.replace(paths) + $".replace(loaded) + end + + def test_resolve_feature_path_with_missing_feature + assert_nil($LOAD_PATH.resolve_feature_path("superkalifragilisticoespialidoso")) + end + end + + def test_require_with_public_method_missing + # [Bug #19793] + assert_ruby_status(["-W0", "-rtempfile"], <<~RUBY, timeout: 60) + GC.stress = true + + class Object + public :method_missing + end + + Tempfile.create(["empty", ".rb"]) do |file| + require file.path + end + RUBY + end + + def test_bug_21568 + load_path = $LOAD_PATH.dup + loaded_featrures = $LOADED_FEATURES.dup + + $LOAD_PATH.clear + $LOADED_FEATURES.replace(["foo.so", "a/foo.rb", "b/foo.rb"]) + + assert_nothing_raised(LoadError) { require "foo" } + + ensure + $LOAD_PATH.replace(load_path) if load_path + $LOADED_FEATURES.replace loaded_featrures end end |
