require 'test/unit' require 'tempfile' require_relative 'envutil' class TestRequire < Test::Unit::TestCase def test_require_invalid_shared_object t = Tempfile.new(["test_ruby_test_require", ".so"]) t.puts "dummy" t.close assert_in_out_err([], <<-INPUT, %w(:ok), []) begin require \"#{ t.path }\" rescue LoadError p :ok end INPUT end def test_require_too_long_filename assert_in_out_err([], <<-INPUT, %w(:ok), []) begin require '#{ "foo/" * 10000 }foo' rescue LoadError p :ok end INPUT begin assert_in_out_err(["-S", "foo/" * 10000 + "foo"], "") do |r, e| assert_equal([], r) assert_operator(2, :<=, e.size) assert_equal("openpath: pathname too long (ignored)", e.first) assert_match(/\(LoadError\)/, e.last) end rescue Errno::EINVAL # too long commandline may be blocked by OS. end end def test_require_path_home env_rubypath, env_home = ENV["RUBYPATH"], ENV["HOME"] ENV["RUBYPATH"] = "~" ENV["HOME"] = "/foo" * 10000 assert_in_out_err(%w(-S test_ruby_test_require), "", [], /^.+$/) ENV["RUBYPATH"] = "~" + "/foo" * 10000 ENV["HOME"] = "/foo" assert_in_out_err(%w(-S test_ruby_test_require), "", [], /^.+$/) t = Tempfile.new(["test_ruby_test_require", ".rb"]) t.puts "p :ok" t.close ENV["RUBYPATH"] = "~" ENV["HOME"], name = File.split(t.path) assert_in_out_err(["-S", name], "", %w(:ok), []) ensure env_rubypath ? ENV["RUBYPATH"] = env_rubypath : ENV.delete("RUBYPATH") env_home ? ENV["HOME"] = env_home : ENV.delete("HOME") end def test_define_class begin require "socket" rescue LoadError return end assert_in_out_err([], <<-INPUT, %w(:ok), []) BasicSocket = 1 begin require 'socket' p :ng rescue TypeError p :ok end INPUT assert_in_out_err([], <<-INPUT, %w(:ok), []) class BasicSocket; end begin require 'socket' p :ng rescue NameError p :ok end INPUT assert_in_out_err([], <<-INPUT, %w(:ok), []) class BasicSocket < IO; end begin require 'socket' p :ok rescue Exception p :ng end INPUT end def test_define_class_under begin require "zlib" rescue LoadError return end assert_in_out_err([], <<-INPUT, %w(:ok), []) module Zlib; end Zlib::Error = 1 begin require 'zlib' p :ng rescue TypeError p :ok end INPUT assert_in_out_err([], <<-INPUT, %w(:ok), []) module Zlib; end class Zlib::Error; end begin require 'zlib' p :ng rescue NameError p :ok end INPUT assert_in_out_err([], <<-INPUT, %w(:ok), []) module Zlib; end class Zlib::Error < StandardError; end begin require 'zlib' p :ok rescue Exception p :ng end INPUT end def test_define_module begin require "zlib" rescue LoadError return end assert_in_out_err([], <<-INPUT, %w(:ok), []) Zlib = 1 begin require 'zlib' p :ng rescue TypeError p :ok end INPUT end def test_define_module_under begin require "socket" rescue LoadError return end assert_in_out_err([], <<-INPUT, %w(:ok), []) class BasicSocket < IO; end class Socket < BasicSocket; end Socket::Constants = 1 begin require 'socket' p :ng rescue TypeError p :ok end INPUT end def test_load t = Tempfile.new(["test_ruby_test_require", ".rb"]) t.puts "module Foo; end" t.puts "at_exit { p :wrap_end }" t.puts "at_exit { raise 'error in at_exit test' }" t.puts "p :ok" t.close assert_in_out_err([], <<-INPUT, %w(:ok :end :wrap_end), /error in at_exit test/) load(#{ t.path.dump }, true) GC.start p :end INPUT assert_raise(ArgumentError) { at_exit } end def test_tainted_loadpath t = Tempfile.new(["test_ruby_test_require", ".rb"]) abs_dir, file = File.dirname(t.path), File.basename(t.path) abs_dir = File.expand_path(abs_dir).untaint assert_in_out_err([], <<-INPUT, %w(:ok), []) abs_dir = "#{ abs_dir }" $: << abs_dir require "#{ file }" p :ok INPUT assert_in_out_err([], <<-INPUT, %w(:ok), []) abs_dir = "#{ abs_dir }" $: << abs_dir.taint require "#{ file }" p :ok INPUT assert_in_out_err([], <<-INPUT, %w(:ok), []) abs_dir = "#{ abs_dir }" $: << abs_dir.taint $SAFE = 1 begin require "#{ file }" rescue SecurityError p :ok end INPUT assert_in_out_err([], <<-INPUT, %w(:ok), []) abs_dir = "#{ abs_dir }" $: << abs_dir.taint $SAFE = 1 begin require "#{ file }" rescue SecurityError p :ok end INPUT assert_in_out_err([], <<-INPUT, %w(:ok), []) abs_dir = "#{ abs_dir }" $: << abs_dir << 'elsewhere'.taint require "#{ file }" p :ok INPUT end end