2017-05-07 08:04:49 -04:00
|
|
|
# encoding: utf-8
|
|
|
|
|
2018-03-04 10:09:32 -05:00
|
|
|
require_relative '../../spec_helper'
|
|
|
|
require_relative 'fixtures/common'
|
|
|
|
require_relative 'shared/open'
|
2017-05-07 08:04:49 -04:00
|
|
|
|
|
|
|
describe "File.open" do
|
|
|
|
before :all do
|
|
|
|
@file = tmp("file_open.txt")
|
|
|
|
@unicode_path = tmp("こんにちは.txt")
|
|
|
|
@nonexistent = tmp("fake.txt")
|
|
|
|
rm_r @file, @nonexistent
|
|
|
|
end
|
|
|
|
|
|
|
|
before :each do
|
|
|
|
ScratchPad.record []
|
|
|
|
|
|
|
|
@fh = @fd = nil
|
|
|
|
@flags = File::CREAT | File::TRUNC | File::WRONLY
|
|
|
|
touch @file
|
|
|
|
end
|
|
|
|
|
|
|
|
after :each do
|
|
|
|
@fh.close if @fh and not @fh.closed?
|
|
|
|
rm_r @file, @unicode_path, @nonexistent
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "with a block" do
|
|
|
|
it "does not raise error when file is closed inside the block" do
|
|
|
|
@fh = File.open(@file) { |fh| fh.close; fh }
|
2020-05-03 06:28:29 -04:00
|
|
|
@fh.should.closed?
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "invokes close on an opened file when exiting the block" do
|
|
|
|
File.open(@file, 'r') { |f| FileSpecs.make_closer f }
|
|
|
|
|
|
|
|
ScratchPad.recorded.should == [:file_opened, :file_closed]
|
|
|
|
end
|
|
|
|
|
|
|
|
it "propagates non-StandardErrors produced by close" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, 'r') { |f| FileSpecs.make_closer f, Exception }
|
|
|
|
}.should raise_error(Exception)
|
|
|
|
|
|
|
|
ScratchPad.recorded.should == [:file_opened, :file_closed]
|
|
|
|
end
|
|
|
|
|
|
|
|
it "propagates StandardErrors produced by close" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, 'r') { |f| FileSpecs.make_closer f, StandardError }
|
|
|
|
}.should raise_error(StandardError)
|
|
|
|
|
|
|
|
ScratchPad.recorded.should == [:file_opened, :file_closed]
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not propagate IOError with 'closed stream' message produced by close" do
|
|
|
|
File.open(@file, 'r') { |f| FileSpecs.make_closer f, IOError.new('closed stream') }
|
|
|
|
|
|
|
|
ScratchPad.recorded.should == [:file_opened, :file_closed]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens the file (basic case)" do
|
|
|
|
@fh = File.open(@file)
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens the file with unicode characters" do
|
|
|
|
@fh = File.open(@unicode_path, "w")
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@unicode_path)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file when called with a block" do
|
|
|
|
File.open(@file) { |fh| }
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens with mode string" do
|
|
|
|
@fh = File.open(@file, 'w')
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file with mode string and block" do
|
|
|
|
File.open(@file, 'w') { |fh| }
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file with mode num" do
|
|
|
|
@fh = File.open(@file, @flags)
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file with mode num and block" do
|
|
|
|
File.open(@file, 'w') { |fh| }
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file with mode and permission as nil" do
|
|
|
|
@fh = File.open(@file, nil, nil)
|
|
|
|
@fh.should be_kind_of(File)
|
|
|
|
end
|
|
|
|
|
|
|
|
# For this test we delete the file first to reset the perms
|
|
|
|
it "opens the file when passed mode, num and permissions" do
|
|
|
|
rm_r @file
|
|
|
|
File.umask(0011)
|
|
|
|
@fh = File.open(@file, @flags, 0755)
|
|
|
|
@fh.should be_kind_of(File)
|
|
|
|
platform_is_not :windows do
|
|
|
|
@fh.lstat.mode.to_s(8).should == "100744"
|
|
|
|
end
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# For this test we delete the file first to reset the perms
|
|
|
|
it "opens the file when passed mode, num, permissions and block" do
|
|
|
|
rm_r @file
|
|
|
|
File.umask(0022)
|
|
|
|
File.open(@file, "w", 0755){ |fh| }
|
|
|
|
platform_is_not :windows do
|
|
|
|
File.stat(@file).mode.to_s(8).should == "100755"
|
|
|
|
end
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "creates the file and returns writable descriptor when called with 'w' mode and r-o permissions" do
|
2019-02-07 11:35:33 -05:00
|
|
|
# it should be possible to write to such a file via returned descriptor,
|
2017-05-07 08:04:49 -04:00
|
|
|
# even though the file permissions are r-r-r.
|
|
|
|
|
|
|
|
File.open(@file, "w", 0444) { |f| f.write("test") }
|
|
|
|
File.read(@file).should == "test"
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :windows do
|
|
|
|
it "opens the existing file, does not change permissions even when they are specified" do
|
|
|
|
File.chmod(0664, @file)
|
|
|
|
orig_perms = File.stat(@file).mode.to_s(8)
|
|
|
|
File.open(@file, "w", 0444) { |f| f.write("test") }
|
|
|
|
|
|
|
|
File.stat(@file).mode.to_s(8).should == orig_perms
|
|
|
|
File.read(@file).should == "test"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :windows do
|
2018-01-10 08:30:25 -05:00
|
|
|
as_user do
|
|
|
|
it "creates a new write-only file when invoked with 'w' and '0222'" do
|
|
|
|
rm_r @file
|
|
|
|
File.open(@file, 'w', 0222) {}
|
|
|
|
File.readable?(@file).should == false
|
|
|
|
File.writable?(@file).should == true
|
|
|
|
end
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens the file when call with fd" do
|
|
|
|
@fh = File.open(@file)
|
|
|
|
fh_copy = File.open(@fh.fileno)
|
|
|
|
fh_copy.autoclose = false
|
|
|
|
fh_copy.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file that no exists when use File::WRONLY mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@nonexistent, File::WRONLY) }.should raise_error(Errno::ENOENT)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file that no exists when use File::RDONLY mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@nonexistent, File::RDONLY) }.should raise_error(Errno::ENOENT)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file that no exists when use 'r' mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@nonexistent, 'r') }.should raise_error(Errno::ENOENT)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file that no exists when use File::EXCL mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@nonexistent, File::EXCL) }.should raise_error(Errno::ENOENT)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file that no exists when use File::NONBLOCK mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@nonexistent, File::NONBLOCK) }.should raise_error(Errno::ENOENT)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :openbsd, :windows do
|
|
|
|
it "opens a file that no exists when use File::TRUNC mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@nonexistent, File::TRUNC) }.should raise_error(Errno::ENOENT)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is :openbsd, :windows do
|
|
|
|
it "does not open a file that does no exists when using File::TRUNC mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@nonexistent, File::TRUNC) }.should raise_error(Errno::EINVAL)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :windows do
|
|
|
|
it "opens a file that no exists when use File::NOCTTY mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@nonexistent, File::NOCTTY) }.should raise_error(Errno::ENOENT)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file that no exists when use File::CREAT mode" do
|
|
|
|
@fh = File.open(@nonexistent, File::CREAT) { |f| f }
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file that no exists when use 'a' mode" do
|
|
|
|
@fh = File.open(@nonexistent, 'a') { |f| f }
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file that no exists when use 'w' mode" do
|
|
|
|
@fh = File.open(@nonexistent, 'w') { |f| f }
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
2019-02-07 11:35:33 -05:00
|
|
|
# Check the grants associated to the different open modes combinations.
|
2017-05-07 08:04:49 -04:00
|
|
|
it "raises an ArgumentError exception when call with an unknown mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@file, "q") }.should raise_error(ArgumentError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "can read in a block when call open with RDONLY mode" do
|
|
|
|
File.open(@file, File::RDONLY) do |f|
|
|
|
|
f.gets.should == nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can read in a block when call open with 'r' mode" do
|
|
|
|
File.open(@file, "r") do |f|
|
|
|
|
f.gets.should == nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IO exception when write in a block opened with RDONLY mode" do
|
|
|
|
File.open(@file, File::RDONLY) do |f|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { f.puts "writing ..." }.should raise_error(IOError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IO exception when write in a block opened with 'r' mode" do
|
|
|
|
File.open(@file, "r") do |f|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { f.puts "writing ..." }.should raise_error(IOError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can't write in a block when call open with File::WRONLY||File::RDONLY mode" do
|
|
|
|
File.open(@file, File::WRONLY|File::RDONLY ) do |f|
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can't read in a block when call open with File::WRONLY||File::RDONLY mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::WRONLY|File::RDONLY ) do |f|
|
|
|
|
f.gets.should == nil
|
|
|
|
end
|
|
|
|
}.should raise_error(IOError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can write in a block when call open with WRONLY mode" do
|
|
|
|
File.open(@file, File::WRONLY) do |f|
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can write in a block when call open with 'w' mode" do
|
|
|
|
File.open(@file, "w") do |f|
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IOError when read in a block opened with WRONLY mode" do
|
|
|
|
File.open(@file, File::WRONLY) do |f|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { f.gets }.should raise_error(IOError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IOError when read in a block opened with 'w' mode" do
|
|
|
|
File.open(@file, "w") do |f|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { f.gets }.should raise_error(IOError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IOError when read in a block opened with 'a' mode" do
|
|
|
|
File.open(@file, "a") do |f|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { f.gets }.should raise_error(IOError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IOError when read in a block opened with 'a' mode" do
|
|
|
|
File.open(@file, "a") do |f|
|
|
|
|
f.puts("writing").should == nil
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { f.gets }.should raise_error(IOError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IOError when read in a block opened with 'a' mode" do
|
|
|
|
File.open(@file, File::WRONLY|File::APPEND ) do |f|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { f.gets }.should raise_error(IOError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IOError when read in a block opened with File::WRONLY|File::APPEND mode" do
|
|
|
|
File.open(@file, File::WRONLY|File::APPEND ) do |f|
|
|
|
|
f.puts("writing").should == nil
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { f.gets }.should raise_error(IOError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IOError when read in a block opened with File::RDONLY|File::APPEND mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::RDONLY|File::APPEND ) do |f|
|
|
|
|
f.puts("writing")
|
|
|
|
end
|
|
|
|
}.should raise_error(IOError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can read and write in a block when call open with RDWR mode" do
|
|
|
|
File.open(@file, File::RDWR) do |f|
|
|
|
|
f.gets.should == nil
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
f.rewind
|
|
|
|
f.gets.should == "writing\n"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can't read in a block when call open with File::EXCL mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::EXCL) do |f|
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
end
|
|
|
|
}.should raise_error(IOError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can read in a block when call open with File::EXCL mode" do
|
|
|
|
File.open(@file, File::EXCL) do |f|
|
|
|
|
f.gets.should == nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can read and write in a block when call open with File::RDWR|File::EXCL mode" do
|
|
|
|
File.open(@file, File::RDWR|File::EXCL) do |f|
|
|
|
|
f.gets.should == nil
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
f.rewind
|
|
|
|
f.gets.should == "writing\n"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an Errorno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::CREAT|File::EXCL) do |f|
|
|
|
|
f.puts("writing")
|
|
|
|
end
|
|
|
|
}.should raise_error(Errno::EEXIST)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates a new file when use File::WRONLY|File::APPEND mode" do
|
|
|
|
@fh = File.open(@file, File::WRONLY|File::APPEND)
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file when use File::WRONLY|File::APPEND mode" do
|
|
|
|
File.open(@file, File::WRONLY) do |f|
|
|
|
|
f.puts("hello file")
|
|
|
|
end
|
|
|
|
File.open(@file, File::RDWR|File::APPEND) do |f|
|
|
|
|
f.puts("bye file")
|
|
|
|
f.rewind
|
|
|
|
f.gets.should == "hello file\n"
|
|
|
|
f.gets.should == "bye file\n"
|
|
|
|
f.gets.should == nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an IOError if the file exists when open with File::RDONLY|File::APPEND" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::RDONLY|File::APPEND) do |f|
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
end
|
|
|
|
}.should raise_error(IOError)
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :openbsd, :windows do
|
|
|
|
it "truncates the file when passed File::TRUNC mode" do
|
|
|
|
File.open(@file, File::RDWR) { |f| f.puts "hello file" }
|
|
|
|
@fh = File.open(@file, File::TRUNC)
|
|
|
|
@fh.gets.should == nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can't read in a block when call open with File::TRUNC mode" do
|
|
|
|
File.open(@file, File::TRUNC) do |f|
|
|
|
|
f.gets.should == nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file when use File::WRONLY|File::TRUNC mode" do
|
|
|
|
fh1 = File.open(@file, "w")
|
|
|
|
begin
|
|
|
|
@fh = File.open(@file, File::WRONLY|File::TRUNC)
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
ensure
|
|
|
|
fh1.close
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :openbsd, :windows do
|
|
|
|
it "can't write in a block when call open with File::TRUNC mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::TRUNC) do |f|
|
|
|
|
f.puts("writing")
|
|
|
|
end
|
|
|
|
}.should raise_error(IOError)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::RDONLY|File::TRUNC) do |f|
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
end
|
|
|
|
}.should raise_error(IOError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is :openbsd, :windows do
|
|
|
|
it "can't write in a block when call open with File::TRUNC mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::TRUNC) do |f|
|
|
|
|
f.puts("writing")
|
|
|
|
end
|
|
|
|
}.should raise_error(Errno::EINVAL)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
File.open(@file, File::RDONLY|File::TRUNC) do |f|
|
|
|
|
f.puts("writing").should == nil
|
|
|
|
end
|
|
|
|
}.should raise_error(Errno::EINVAL)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :windows do
|
2018-01-10 08:30:25 -05:00
|
|
|
as_user do
|
|
|
|
it "raises an Errno::EACCES when opening non-permitted file" do
|
|
|
|
@fh = File.open(@file, "w")
|
|
|
|
@fh.chmod(000)
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { fh1 = File.open(@file); fh1.close }.should raise_error(Errno::EACCES)
|
2018-01-10 08:30:25 -05:00
|
|
|
end
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-10 08:30:25 -05:00
|
|
|
as_user do
|
|
|
|
it "raises an Errno::EACCES when opening read-only file" do
|
|
|
|
@fh = File.open(@file, "w")
|
|
|
|
@fh.chmod(0444)
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@file, "w") }.should raise_error(Errno::EACCES)
|
2018-01-10 08:30:25 -05:00
|
|
|
end
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file for binary read" do
|
|
|
|
@fh = File.open(@file, "rb")
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file for binary write" do
|
|
|
|
@fh = File.open(@file, "wb")
|
|
|
|
@fh.should be_kind_of(File)
|
2019-09-29 13:13:37 -04:00
|
|
|
File.should.exist?(@file)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file for read-write and truncate the file" do
|
|
|
|
File.open(@file, "w") { |f| f.puts "testing" }
|
|
|
|
File.size(@file).should > 0
|
|
|
|
File.open(@file, "w+") do |f|
|
|
|
|
f.pos.should == 0
|
2020-05-03 06:28:29 -04:00
|
|
|
f.should.eof?
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
File.size(@file).should == 0
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file for binary read-write starting at the beginning of the file" do
|
|
|
|
File.open(@file, "w") { |f| f.puts "testing" }
|
|
|
|
File.size(@file).should > 0
|
|
|
|
File.open(@file, "rb+") do |f|
|
|
|
|
f.pos.should == 0
|
2020-05-03 06:28:29 -04:00
|
|
|
f.should_not.eof?
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file for binary read-write and truncate the file" do
|
|
|
|
File.open(@file, "w") { |f| f.puts "testing" }
|
|
|
|
File.size(@file).should > 0
|
|
|
|
File.open(@file, "wb+") do |f|
|
|
|
|
f.pos.should == 0
|
2020-05-03 06:28:29 -04:00
|
|
|
f.should.eof?
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
File.size(@file).should == 0
|
|
|
|
end
|
|
|
|
|
2018-04-28 15:50:06 -04:00
|
|
|
platform_is :linux do
|
|
|
|
guard -> { defined?(File::TMPFILE) } do
|
|
|
|
it "creates an unnamed temporary file with File::TMPFILE" do
|
|
|
|
dir = tmp("tmpfilespec")
|
|
|
|
mkdir_p dir
|
|
|
|
begin
|
|
|
|
Dir["#{dir}/*"].should == []
|
|
|
|
File.open(dir, "r+", flags: File::TMPFILE) do |io|
|
|
|
|
io.write("ruby")
|
|
|
|
io.flush
|
|
|
|
io.rewind
|
|
|
|
io.read.should == "ruby"
|
2017-06-01 13:08:59 -04:00
|
|
|
Dir["#{dir}/*"].should == []
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
2019-09-29 13:13:37 -04:00
|
|
|
rescue Errno::EOPNOTSUPP
|
|
|
|
skip "no support from the filesystem"
|
|
|
|
rescue Errno::EINVAL, Errno::EISDIR
|
|
|
|
skip "presumably bug in glibc"
|
2018-04-28 15:50:06 -04:00
|
|
|
ensure
|
|
|
|
rm_r dir
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises a TypeError if passed a filename that is not a String or Integer type" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(true) }.should raise_error(TypeError)
|
|
|
|
-> { File.open(false) }.should raise_error(TypeError)
|
|
|
|
-> { File.open(nil) }.should raise_error(TypeError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "raises a SystemCallError if passed an invalid Integer type" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(-1) }.should raise_error(SystemCallError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an ArgumentError if passed the wrong number of arguments" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@file, File::CREAT, 0755, 'test') }.should raise_error(ArgumentError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an ArgumentError if passed an invalid string for mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@file, 'fake') }.should raise_error(ArgumentError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
2019-06-27 15:02:36 -04:00
|
|
|
it "defaults external_encoding to BINARY for binary modes" do
|
|
|
|
File.open(@file, 'rb') {|f| f.external_encoding.should == Encoding::BINARY}
|
|
|
|
File.open(@file, 'wb+') {|f| f.external_encoding.should == Encoding::BINARY}
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "uses the second argument as an options Hash" do
|
|
|
|
@fh = File.open(@file, mode: "r")
|
|
|
|
@fh.should be_an_instance_of(File)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "calls #to_hash to convert the second argument to a Hash" do
|
|
|
|
options = mock("file open options")
|
|
|
|
options.should_receive(:to_hash).and_return({ mode: "r" })
|
|
|
|
|
2019-09-29 10:03:58 -04:00
|
|
|
@fh = File.open(@file, **options)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
2018-04-28 15:50:06 -04:00
|
|
|
it "accepts extra flags as a keyword argument and combine with a string mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2018-04-28 15:50:06 -04:00
|
|
|
File.open(@file, "w", flags: File::EXCL) { }
|
|
|
|
}.should raise_error(Errno::EEXIST)
|
2017-05-07 08:04:49 -04:00
|
|
|
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2018-04-28 15:50:06 -04:00
|
|
|
File.open(@file, mode: "w", flags: File::EXCL) { }
|
|
|
|
}.should raise_error(Errno::EEXIST)
|
|
|
|
end
|
2017-05-07 08:04:49 -04:00
|
|
|
|
2018-04-28 15:50:06 -04:00
|
|
|
it "accepts extra flags as a keyword argument and combine with an integer mode" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2018-04-28 15:50:06 -04:00
|
|
|
File.open(@file, File::WRONLY | File::CREAT, flags: File::EXCL) { }
|
|
|
|
}.should raise_error(Errno::EEXIST)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :windows do
|
|
|
|
describe "on a FIFO" do
|
|
|
|
before :each do
|
|
|
|
@fifo = tmp("File_open_fifo")
|
2018-06-13 17:58:54 -04:00
|
|
|
File.mkfifo(@fifo)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
after :each do
|
|
|
|
rm_r @fifo
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens it as a normal file" do
|
|
|
|
file_w, file_r, read_bytes, written_length = nil
|
|
|
|
|
|
|
|
# open in threads, due to blocking open and writes
|
|
|
|
writer = Thread.new do
|
|
|
|
file_w = File.open(@fifo, 'w')
|
|
|
|
written_length = file_w.syswrite('hello')
|
|
|
|
end
|
|
|
|
reader = Thread.new do
|
|
|
|
file_r = File.open(@fifo, 'r')
|
|
|
|
read_bytes = file_r.sysread(5)
|
|
|
|
end
|
|
|
|
|
|
|
|
begin
|
|
|
|
writer.join
|
|
|
|
reader.join
|
|
|
|
|
|
|
|
written_length.should == 5
|
|
|
|
read_bytes.should == 'hello'
|
|
|
|
ensure
|
|
|
|
file_w.close if file_w
|
|
|
|
file_r.close if file_r
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-02-08 05:43:27 -05:00
|
|
|
it "raises ArgumentError if mixing :newline and binary mode" do
|
|
|
|
-> {
|
|
|
|
File.open(@file, "rb", newline: :universal) {}
|
|
|
|
}.should raise_error(ArgumentError, "newline decorator with binary mode")
|
2019-11-30 15:26:52 -05:00
|
|
|
end
|
|
|
|
|
2019-01-20 15:38:57 -05:00
|
|
|
ruby_version_is "2.6" do
|
|
|
|
context "'x' flag" do
|
|
|
|
before :each do
|
|
|
|
@xfile = tmp("x-flag")
|
|
|
|
rm_r @xfile
|
|
|
|
end
|
|
|
|
|
|
|
|
after :each do
|
|
|
|
rm_r @xfile
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does nothing if the file doesn't exist" do
|
|
|
|
File.open(@xfile, "wx") { |f| f.write("content") }
|
|
|
|
File.read(@xfile).should == "content"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "throws a Errno::EEXIST error if the file exists" do
|
|
|
|
touch @xfile
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@xfile, "wx") }.should raise_error(Errno::EEXIST)
|
2019-01-20 15:38:57 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "can't be used with 'r' and 'a' flags" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { File.open(@xfile, "rx") }.should raise_error(ArgumentError, 'invalid access mode rx')
|
|
|
|
-> { File.open(@xfile, "ax") }.should raise_error(ArgumentError, 'invalid access mode ax')
|
2019-01-20 15:38:57 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
describe "File.open when passed a file descriptor" do
|
|
|
|
before do
|
|
|
|
@content = "File#open when passed a file descriptor"
|
|
|
|
@name = tmp("file_open_with_fd.txt")
|
2019-04-28 17:20:11 -04:00
|
|
|
@fd = new_fd @name, "w:utf-8"
|
2017-05-07 08:04:49 -04:00
|
|
|
@file = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
after do
|
|
|
|
@file.close if @file and not @file.closed?
|
|
|
|
rm_r @name
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file" do
|
|
|
|
@file = File.open(@fd, "w")
|
|
|
|
@file.should be_an_instance_of(File)
|
|
|
|
@file.fileno.should equal(@fd)
|
|
|
|
@file.write @content
|
|
|
|
@file.flush
|
|
|
|
File.read(@name).should == @content
|
|
|
|
end
|
|
|
|
|
|
|
|
it "opens a file when passed a block" do
|
|
|
|
@file = File.open(@fd, "w") do |f|
|
|
|
|
f.should be_an_instance_of(File)
|
|
|
|
f.fileno.should equal(@fd)
|
|
|
|
f.write @content
|
|
|
|
f
|
|
|
|
end
|
|
|
|
File.read(@name).should == @content
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
platform_is_not :windows do
|
|
|
|
describe "File.open" do
|
|
|
|
it_behaves_like :open_directory, :open
|
|
|
|
end
|
|
|
|
end
|