summaryrefslogtreecommitdiff
path: root/spec/rubyspec/core/kernel/shared/require.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/rubyspec/core/kernel/shared/require.rb')
-rw-r--r--spec/rubyspec/core/kernel/shared/require.rb703
1 files changed, 0 insertions, 703 deletions
diff --git a/spec/rubyspec/core/kernel/shared/require.rb b/spec/rubyspec/core/kernel/shared/require.rb
deleted file mode 100644
index 3296c7f42a..0000000000
--- a/spec/rubyspec/core/kernel/shared/require.rb
+++ /dev/null
@@ -1,703 +0,0 @@
-describe :kernel_require_basic, shared: true do
- describe "(path resolution)" do
- it "loads an absolute path" do
- path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
- @object.send(@method, path).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a non-canonical absolute path" do
- path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb"
- @object.send(@method, path).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a file defining many methods" do
- path = File.expand_path "methods_fixture.rb", CODE_LOADING_DIR
- @object.send(@method, path).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "raises a LoadError if the file does not exist" do
- path = File.expand_path "nonexistent.rb", CODE_LOADING_DIR
- File.exist?(path).should be_false
- lambda { @object.send(@method, path) }.should raise_error(LoadError)
- ScratchPad.recorded.should == []
- end
-
- # Can't make a file unreadable on these platforms
- platform_is_not :windows, :cygwin do
- describe "with an unreadable file" do
- before :each do
- @path = tmp("unreadable_file.rb")
- touch @path
- File.chmod 0000, @path
- end
-
- after :each do
- File.chmod 0666, @path
- rm_r @path
- end
-
- it "raises a LoadError" do
- File.exist?(@path).should be_true
- lambda { @object.send(@method, @path) }.should raise_error(LoadError)
- end
- end
- end
-
- it "calls #to_str on non-String objects" do
- path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
- name = mock("load_fixture.rb mock")
- name.should_receive(:to_str).and_return(path)
- @object.send(@method, name).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "raises a TypeError if passed nil" do
- lambda { @object.send(@method, nil) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError if passed a Fixnum" do
- lambda { @object.send(@method, 42) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError if passed an Array" do
- lambda { @object.send(@method, []) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError if passed an object that does not provide #to_str" do
- lambda { @object.send(@method, mock("not a filename")) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError if passed an object that has #to_s but not #to_str" do
- name = mock("load_fixture.rb mock")
- name.stub!(:to_s).and_return("load_fixture.rb")
- $LOAD_PATH << "."
- Dir.chdir CODE_LOADING_DIR do
- lambda { @object.send(@method, name) }.should raise_error(TypeError)
- end
- end
-
- it "raises a TypeError if #to_str does not return a String" do
- name = mock("#to_str returns nil")
- name.should_receive(:to_str).at_least(1).times.and_return(nil)
- lambda { @object.send(@method, name) }.should raise_error(TypeError)
- end
-
- it "calls #to_path on non-String objects" do
- name = mock("load_fixture.rb mock")
- name.stub!(:to_path).and_return("load_fixture.rb")
- $LOAD_PATH << "."
- Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, name).should be_true
- end
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "calls #to_path on a String" do
- path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
- str = mock("load_fixture.rb mock")
- str.should_receive(:to_path).and_return(path)
- @object.send(@method, str).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "calls #to_str on non-String objects returned by #to_path" do
- path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
- name = mock("load_fixture.rb mock")
- to_path = mock("load_fixture_rb #to_path mock")
- name.should_receive(:to_path).and_return(to_path)
- to_path.should_receive(:to_str).and_return(path)
- @object.send(@method, name).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- # "http://redmine.ruby-lang.org/issues/show/2578"
- it "loads a ./ relative path from the current working directory with empty $LOAD_PATH" do
- Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "./load_fixture.rb").should be_true
- end
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a ../ relative path from the current working directory with empty $LOAD_PATH" do
- Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/load_fixture.rb").should be_true
- end
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a ./ relative path from the current working directory with non-empty $LOAD_PATH" do
- $LOAD_PATH << "an_irrelevant_dir"
- Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "./load_fixture.rb").should be_true
- end
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a ../ relative path from the current working directory with non-empty $LOAD_PATH" do
- $LOAD_PATH << "an_irrelevant_dir"
- Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/load_fixture.rb").should be_true
- end
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a non-canonical path from the current working directory with non-empty $LOAD_PATH" do
- $LOAD_PATH << "an_irrelevant_dir"
- Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/../code/load_fixture.rb").should be_true
- end
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "resolves a filename against $LOAD_PATH entries" do
- $LOAD_PATH << CODE_LOADING_DIR
- @object.send(@method, "load_fixture.rb").should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "does not require file twice after $LOAD_PATH change" do
- $LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture.rb").should be_true
- $LOAD_PATH.unshift CODE_LOADING_DIR + "/gem"
- @object.require("load_fixture.rb").should be_false
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "does not resolve a ./ relative path against $LOAD_PATH entries" do
- $LOAD_PATH << CODE_LOADING_DIR
- lambda do
- @object.send(@method, "./load_fixture.rb")
- end.should raise_error(LoadError)
- ScratchPad.recorded.should == []
- end
-
- it "does not resolve a ../ relative path against $LOAD_PATH entries" do
- $LOAD_PATH << CODE_LOADING_DIR
- lambda do
- @object.send(@method, "../code/load_fixture.rb")
- end.should raise_error(LoadError)
- ScratchPad.recorded.should == []
- end
-
- it "resolves a non-canonical path against $LOAD_PATH entries" do
- $LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.send(@method, "code/../code/load_fixture.rb").should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a path with duplicate path separators" do
- $LOAD_PATH << "."
- sep = File::Separator + File::Separator
- path = ["..", "code", "load_fixture.rb"].join(sep)
- Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, path).should be_true
- end
- ScratchPad.recorded.should == [:loaded]
- end
- end
-end
-
-describe :kernel_require, shared: true do
- describe "(path resolution)" do
- # For reference see [ruby-core:24155] in which matz confirms this feature is
- # intentional for security reasons.
- it "does not load a bare filename unless the current working directory is in $LOAD_PATH" do
- Dir.chdir CODE_LOADING_DIR do
- lambda { @object.require("load_fixture.rb") }.should raise_error(LoadError)
- ScratchPad.recorded.should == []
- end
- end
-
- it "does not load a relative path unless the current working directory is in $LOAD_PATH" do
- Dir.chdir File.dirname(CODE_LOADING_DIR) do
- lambda do
- @object.require("code/load_fixture.rb")
- end.should raise_error(LoadError)
- ScratchPad.recorded.should == []
- end
- end
-
- it "loads a file that recursively requires itself" do
- path = File.expand_path "recursive_require_fixture.rb", CODE_LOADING_DIR
- -> {
- $VERBOSE = true
- @object.require(path).should be_true
- }.should complain(/circular require considered harmful/)
- ScratchPad.recorded.should == [:loaded]
- end
- end
-
- describe "(non-extensioned path)" do
- before :each do
- a = File.expand_path "a", CODE_LOADING_DIR
- b = File.expand_path "b", CODE_LOADING_DIR
- $LOAD_PATH.replace [a, b]
- end
-
- it "loads a .rb extensioned file when a C-extension file exists on an earlier load path" do
- @object.require("load_fixture").should be_true
- ScratchPad.recorded.should == [:loaded]
- end
- end
-
- describe "(file extensions)" do
- it "loads a .rb extensioned file when passed a non-extensioned path" do
- path = File.expand_path "load_fixture", CODE_LOADING_DIR
- File.exist?(path).should be_true
- @object.require(path).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a .rb extensioned file when a C-extension file of the same name is loaded" do
- $LOADED_FEATURES << File.expand_path("load_fixture.bundle", CODE_LOADING_DIR)
- $LOADED_FEATURES << File.expand_path("load_fixture.dylib", CODE_LOADING_DIR)
- $LOADED_FEATURES << File.expand_path("load_fixture.so", CODE_LOADING_DIR)
- $LOADED_FEATURES << File.expand_path("load_fixture.dll", CODE_LOADING_DIR)
- path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.require(path).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "does not load a C-extension file if a .rb extensioned file is already loaded" do
- $LOADED_FEATURES << File.expand_path("load_fixture.rb", CODE_LOADING_DIR)
- path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.require(path).should be_false
- ScratchPad.recorded.should == []
- end
-
- it "loads a .rb extensioned file when passed a non-.rb extensioned path" do
- path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- File.exist?(path).should be_true
- @object.require(path).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a .rb extensioned file when a complex-extensioned C-extension file of the same name is loaded" do
- $LOADED_FEATURES << File.expand_path("load_fixture.ext.bundle", CODE_LOADING_DIR)
- $LOADED_FEATURES << File.expand_path("load_fixture.ext.dylib", CODE_LOADING_DIR)
- $LOADED_FEATURES << File.expand_path("load_fixture.ext.so", CODE_LOADING_DIR)
- $LOADED_FEATURES << File.expand_path("load_fixture.ext.dll", CODE_LOADING_DIR)
- path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.require(path).should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "does not load a C-extension file if a complex-extensioned .rb file is already loaded" do
- $LOADED_FEATURES << File.expand_path("load_fixture.ext.rb", CODE_LOADING_DIR)
- path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.require(path).should be_false
- ScratchPad.recorded.should == []
- end
- end
-
- describe "($LOADED_FEATURES)" do
- before :each do
- @path = File.expand_path("load_fixture.rb", CODE_LOADING_DIR)
- end
-
- it "stores an absolute path" do
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
- end
-
- it "does not store the path if the load fails" do
- $LOAD_PATH << CODE_LOADING_DIR
- saved_loaded_features = $LOADED_FEATURES.dup
- lambda { @object.require("raise_fixture.rb") }.should raise_error(RuntimeError)
- $LOADED_FEATURES.should == saved_loaded_features
- end
-
- it "does not load an absolute path that is already stored" do
- $LOADED_FEATURES << @path
- @object.require(@path).should be_false
- ScratchPad.recorded.should == []
- end
-
- it "does not load a ./ relative path that is already stored" do
- $LOADED_FEATURES << "./load_fixture.rb"
- Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_false
- end
- ScratchPad.recorded.should == []
- end
-
- it "does not load a ../ relative path that is already stored" do
- $LOADED_FEATURES << "../load_fixture.rb"
- Dir.chdir CODE_LOADING_DIR do
- @object.require("../load_fixture.rb").should be_false
- end
- ScratchPad.recorded.should == []
- end
-
- it "does not load a non-canonical path that is already stored" do
- $LOADED_FEATURES << "code/../code/load_fixture.rb"
- $LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/../code/load_fixture.rb").should be_false
- ScratchPad.recorded.should == []
- end
-
- it "respects being replaced with a new array" do
- prev = $LOADED_FEATURES.dup
-
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
-
- $LOADED_FEATURES.replace(prev)
-
- $LOADED_FEATURES.should_not include(@path)
- @object.require(@path).should be_true
- $LOADED_FEATURES.should include(@path)
- end
-
- it "does not load twice the same file with and without extension" do
- $LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture.rb").should be_true
- @object.require("load_fixture").should be_false
- end
-
- describe "when a non-extensioned file is in $LOADED_FEATURES" do
- before :each do
- $LOADED_FEATURES << "load_fixture"
- end
-
- it "loads a .rb extensioned file when a non extensioned file is in $LOADED_FEATURES" do
- $LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture").should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "loads a .rb extensioned file from a subdirectory" do
- $LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/load_fixture").should be_true
- ScratchPad.recorded.should == [:loaded]
- end
-
- it "returns false if the file is not found" do
- Dir.chdir File.dirname(CODE_LOADING_DIR) do
- @object.require("load_fixture").should be_false
- ScratchPad.recorded.should == []
- end
- end
-
- it "returns false when passed a path and the file is not found" do
- $LOADED_FEATURES << "code/load_fixture"
- Dir.chdir CODE_LOADING_DIR do
- @object.require("code/load_fixture").should be_false
- ScratchPad.recorded.should == []
- end
- end
- end
-
- it "stores ../ relative paths as absolute paths" do
- Dir.chdir CODE_LOADING_DIR do
- @object.require("../code/load_fixture.rb").should be_true
- end
- $LOADED_FEATURES.should include(@path)
- end
-
- it "stores ./ relative paths as absolute paths" do
- Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_true
- end
- $LOADED_FEATURES.should include(@path)
- end
-
- it "collapses duplicate path separators" do
- $LOAD_PATH << "."
- sep = File::Separator + File::Separator
- path = ["..", "code", "load_fixture.rb"].join(sep)
- Dir.chdir CODE_LOADING_DIR do
- @object.require(path).should be_true
- end
- $LOADED_FEATURES.should include(@path)
- end
-
- it "canonicalizes non-unique absolute paths" do
- path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb"
- @object.require(path).should be_true
- $LOADED_FEATURES.should include(@path)
- end
-
- it "adds the suffix of the resolved filename" do
- $LOAD_PATH << CODE_LOADING_DIR
- @object.require("load_fixture").should be_true
- $LOADED_FEATURES.should include(@path)
- end
-
- it "does not load a non-canonical path for a file already loaded" do
- $LOADED_FEATURES << @path
- $LOAD_PATH << File.dirname(CODE_LOADING_DIR)
- @object.require("code/../code/load_fixture.rb").should be_false
- ScratchPad.recorded.should == []
- end
-
- it "does not load a ./ relative path for a file already loaded" do
- $LOADED_FEATURES << @path
- $LOAD_PATH << "an_irrelevant_dir"
- Dir.chdir CODE_LOADING_DIR do
- @object.require("./load_fixture.rb").should be_false
- end
- ScratchPad.recorded.should == []
- end
-
- it "does not load a ../ relative path for a file already loaded" do
- $LOADED_FEATURES << @path
- $LOAD_PATH << "an_irrelevant_dir"
- Dir.chdir CODE_LOADING_DIR do
- @object.require("../code/load_fixture.rb").should be_false
- end
- ScratchPad.recorded.should == []
- end
-
- ruby_version_is "2.2"..."2.3" do
- it "complex, enumerator, rational and unicode_normalize are already required" do
- provided = %w[complex enumerator rational unicode_normalize]
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so)$/
- }
-
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
- end
-
- ruby_version_is "2.3"..."2.5" do
- it "complex, enumerator, rational, thread and unicode_normalize are already required" do
- provided = %w[complex enumerator rational thread unicode_normalize]
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so|jar)$/
- }
-
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
- end
-
- ruby_version_is "2.5" do
- it "complex, enumerator, rational and thread are already required" do
- provided = %w[complex enumerator rational thread]
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so|jar)$/
- }
-
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
- end
- end
-
- describe "(shell expansion)" do
- before :each do
- @path = File.expand_path("load_fixture.rb", CODE_LOADING_DIR)
- @env_home = ENV["HOME"]
- ENV["HOME"] = CODE_LOADING_DIR
- end
-
- after :each do
- ENV["HOME"] = @env_home
- end
-
- # "#3171"
- it "performs tilde expansion on a .rb file before storing paths in $LOADED_FEATURES" do
- @object.require("~/load_fixture.rb").should be_true
- $LOADED_FEATURES.should include(@path)
- end
-
- it "performs tilde expansion on a non-extensioned file before storing paths in $LOADED_FEATURES" do
- @object.require("~/load_fixture").should be_true
- $LOADED_FEATURES.should include(@path)
- end
- end
-
- describe "(concurrently)" do
- before :each do
- ScratchPad.record []
- @path = File.expand_path "concurrent.rb", CODE_LOADING_DIR
- @path2 = File.expand_path "concurrent2.rb", CODE_LOADING_DIR
- @path3 = File.expand_path "concurrent3.rb", CODE_LOADING_DIR
- end
-
- after :each do
- ScratchPad.clear
- $LOADED_FEATURES.delete @path
- $LOADED_FEATURES.delete @path2
- $LOADED_FEATURES.delete @path3
- end
-
- # Quick note about these specs:
- #
- # The behavior we're spec'ing requires that t2 enter #require, see t1 is
- # loading @path, grab a lock, and wait on it.
- #
- # We do make sure that t2 starts the require once t1 is in the middle
- # of concurrent.rb, but we then need to get t2 to get far enough into #require
- # to see t1's lock and try to lock it.
- it "blocks a second thread from returning while the 1st is still requiring" do
- fin = false
-
- t1_res = nil
- t2_res = nil
-
- t2 = nil
- t1 = Thread.new do
- Thread.pass until t2
- Thread.current[:wait_for] = t2
- t1_res = @object.require(@path)
- Thread.pass until fin
- ScratchPad.recorded << :t1_post
- end
-
- t2 = Thread.new do
- Thread.pass until t1[:in_concurrent_rb]
- $VERBOSE, @verbose = nil, $VERBOSE
- begin
- t2_res = @object.require(@path)
- ScratchPad.recorded << :t2_post
- ensure
- $VERBOSE = @verbose
- fin = true
- end
- end
-
- t1.join
- t2.join
-
- t1_res.should be_true
- t2_res.should be_false
-
- ScratchPad.recorded.should == [:con_pre, :con_post, :t2_post, :t1_post]
- end
-
- it "blocks based on the path" do
- t1_res = nil
- t2_res = nil
-
- t2 = nil
- t1 = Thread.new do
- Thread.pass until t2
- Thread.current[:concurrent_require_thread] = t2
- t1_res = @object.require(@path2)
- end
-
- t2 = Thread.new do
- Thread.pass until t1[:in_concurrent_rb2]
- t2_res = @object.require(@path3)
- end
-
- t1.join
- t2.join
-
- t1_res.should be_true
- t2_res.should be_true
-
- ScratchPad.recorded.should == [:con2_pre, :con3, :con2_post]
- end
-
- it "allows a 2nd require if the 1st raised an exception" do
- fin = false
-
- t2_res = nil
-
- t2 = nil
- t1 = Thread.new do
- Thread.pass until t2
- Thread.current[:wait_for] = t2
- Thread.current[:con_raise] = true
-
- lambda {
- @object.require(@path)
- }.should raise_error(RuntimeError)
-
- Thread.pass until fin
- ScratchPad.recorded << :t1_post
- end
-
- t2 = Thread.new do
- Thread.pass until t1[:in_concurrent_rb]
- $VERBOSE, @verbose = nil, $VERBOSE
- begin
- t2_res = @object.require(@path)
- ScratchPad.recorded << :t2_post
- ensure
- $VERBOSE = @verbose
- fin = true
- end
- end
-
- t1.join
- t2.join
-
- t2_res.should be_true
-
- ScratchPad.recorded.should == [:con_pre, :con_pre, :con_post, :t2_post, :t1_post]
- end
-
- # "redmine #5754"
- it "blocks a 3rd require if the 1st raises an exception and the 2nd is still running" do
- fin = false
-
- t1_res = nil
- t2_res = nil
-
- raised = false
-
- t2 = nil
- t1 = Thread.new do
- Thread.current[:con_raise] = true
-
- lambda {
- @object.require(@path)
- }.should raise_error(RuntimeError)
-
- raised = true
-
- # This hits the bug. Because MRI removes its internal lock from a table
- # when the exception is raised, this #require doesn't see that t2 is in
- # the middle of requiring the file, so this #require runs when it should not.
- Thread.pass until t2 && t2[:in_concurrent_rb]
- t1_res = @object.require(@path)
-
- Thread.pass until fin
- ScratchPad.recorded << :t1_post
- end
-
- t2 = Thread.new do
- Thread.pass until raised
- Thread.current[:wait_for] = t1
- begin
- t2_res = @object.require(@path)
- ScratchPad.recorded << :t2_post
- ensure
- fin = true
- end
- end
-
- t1.join
- t2.join
-
- t1_res.should be_false
- t2_res.should be_true
-
- ScratchPad.recorded.should == [:con_pre, :con_pre, :con_post, :t2_post, :t1_post]
- end
- end
-
- it "stores the missing path in a LoadError object" do
- path = "abcd1234"
-
- lambda {
- @object.send(@method, path)
- }.should raise_error(LoadError) { |e|
- e.path.should == path
- }
- end
-end