diff options
Diffstat (limited to 'spec/ruby/core/file')
67 files changed, 948 insertions, 687 deletions
diff --git a/spec/ruby/core/file/absolute_path_spec.rb b/spec/ruby/core/file/absolute_path_spec.rb index 52839cf1cc..fc12985a75 100644 --- a/spec/ruby/core/file/absolute_path_spec.rb +++ b/spec/ruby/core/file/absolute_path_spec.rb @@ -1,54 +1,52 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "File.absolute_path?" do - before :each do - @abs = File.expand_path(__FILE__) - end +describe "File.absolute_path?" do + before :each do + @abs = File.expand_path(__FILE__) + end - it "returns true if it's an absolute pathname" do - File.absolute_path?(@abs).should be_true - end + it "returns true if it's an absolute pathname" do + File.absolute_path?(@abs).should == true + end - it "returns false if it's a relative path" do - File.absolute_path?(File.basename(__FILE__)).should be_false - end + it "returns false if it's a relative path" do + File.absolute_path?(File.basename(__FILE__)).should == false + end - it "returns false if it's a tricky relative path" do - File.absolute_path?("C:foo\\bar").should be_false - end + it "returns false if it's a tricky relative path" do + File.absolute_path?("C:foo\\bar").should == false + end - it "does not expand '~' to a home directory." do - File.absolute_path?('~').should be_false - end + it "does not expand '~' to a home directory." do + File.absolute_path?('~').should == false + end - it "does not expand '~user' to a home directory." do - path = File.dirname(@abs) - Dir.chdir(path) do - File.absolute_path?('~user').should be_false - end + it "does not expand '~user' to a home directory." do + path = File.dirname(@abs) + Dir.chdir(path) do + File.absolute_path?('~user').should == false end + end - it "calls #to_path on its argument" do - mock = mock_to_path(File.expand_path(__FILE__)) + it "calls #to_path on its argument" do + mock = mock_to_path(File.expand_path(__FILE__)) - File.absolute_path?(mock).should be_true - end + File.absolute_path?(mock).should == true + end - platform_is_not :windows do - it "takes into consideration the platform's root" do - File.absolute_path?("C:\\foo\\bar").should be_false - File.absolute_path?("C:/foo/bar").should be_false - File.absolute_path?("/foo/bar\\baz").should be_true - end + platform_is_not :windows do + it "takes into consideration the platform's root" do + File.absolute_path?("C:\\foo\\bar").should == false + File.absolute_path?("C:/foo/bar").should == false + File.absolute_path?("/foo/bar\\baz").should == true end + end - platform_is :windows do - it "takes into consideration the platform path separator(s)" do - File.absolute_path?("C:\\foo\\bar").should be_true - File.absolute_path?("C:/foo/bar").should be_true - File.absolute_path?("/foo/bar\\baz").should be_false - end + platform_is :windows do + it "takes into consideration the platform path separator(s)" do + File.absolute_path?("C:\\foo\\bar").should == true + File.absolute_path?("C:/foo/bar").should == true + File.absolute_path?("/foo/bar\\baz").should == false end end end @@ -73,6 +71,12 @@ describe "File.absolute_path" do File.absolute_path('~').should_not == File.expand_path('~') end + platform_is_not :windows do + it "does not expand '~' when given dir argument" do + File.absolute_path('~', '/').should == '/~' + end + end + it "does not expand '~user' to a home directory." do path = File.dirname(@abs) Dir.chdir(path) do @@ -81,7 +85,7 @@ describe "File.absolute_path" do end it "accepts a second argument of a directory from which to resolve the path" do - File.absolute_path(__FILE__, File.dirname(__FILE__)).should == @abs + File.absolute_path(__FILE__, __dir__).should == @abs end it "calls #to_path on its argument" do diff --git a/spec/ruby/core/file/atime_spec.rb b/spec/ruby/core/file/atime_spec.rb index 02e8412722..5c6c110eec 100644 --- a/spec/ruby/core/file/atime_spec.rb +++ b/spec/ruby/core/file/atime_spec.rb @@ -12,25 +12,30 @@ describe "File.atime" do it "returns the last access time for the named file as a Time object" do File.atime(@file) - File.atime(@file).should be_kind_of(Time) - end - - guard -> { platform_is :linux or (platform_is :windows and ruby_version_is '2.5') } do - ## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed. - it "returns the last access time for the named file with microseconds" do - supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d+)/, 1], 10) - if supports_subseconds != 0 - expected_time = Time.at(Time.now.to_i + 0.123456) - File.utime expected_time, 0, @file - File.atime(@file).usec.should == expected_time.usec - else - File.atime(__FILE__).usec.should == 0 + File.atime(@file).should.is_a?(Time) + end + + platform_is :linux, :windows do + unless ENV.key?('TRAVIS') # https://bugs.ruby-lang.org/issues/17926 + ## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed. + it "returns the last access time for the named file with microseconds" do + supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10) + if supports_subseconds != 0 + expected_time = Time.at(Time.now.to_i + 0.123456) + File.utime expected_time, 0, @file + File.atime(@file).usec.should == expected_time.usec + else + File.atime(__FILE__).usec.should == 0 + end + rescue Errno::ENOENT => e + # Native Windows don't have stat command. + skip e.message end end end it "raises an Errno::ENOENT exception if the file is not found" do - -> { File.atime('a_fake_file') }.should raise_error(Errno::ENOENT) + -> { File.atime('a_fake_file') }.should.raise(Errno::ENOENT) end it "accepts an object that has a #to_path method" do @@ -50,6 +55,6 @@ describe "File#atime" do it "returns the last access time to self" do @file.atime - @file.atime.should be_kind_of(Time) + @file.atime.should.is_a?(Time) end end diff --git a/spec/ruby/core/file/basename_spec.rb b/spec/ruby/core/file/basename_spec.rb index 6d7e432086..77afe5c22f 100644 --- a/spec/ruby/core/file/basename_spec.rb +++ b/spec/ruby/core/file/basename_spec.rb @@ -42,7 +42,7 @@ describe "File.basename" do end it "returns an string" do - File.basename("foo").should be_kind_of(String) + File.basename("foo").should.is_a?(String) end it "returns the basename for unix format" do @@ -105,10 +105,10 @@ describe "File.basename" do end it "raises a TypeError if the arguments are not String types" do - -> { File.basename(nil) }.should raise_error(TypeError) - -> { File.basename(1) }.should raise_error(TypeError) - -> { File.basename("bar.txt", 1) }.should raise_error(TypeError) - -> { File.basename(true) }.should raise_error(TypeError) + -> { File.basename(nil) }.should.raise(TypeError) + -> { File.basename(1) }.should.raise(TypeError) + -> { File.basename("bar.txt", 1) }.should.raise(TypeError) + -> { File.basename(true) }.should.raise(TypeError) end it "accepts an object that has a #to_path method" do @@ -116,7 +116,7 @@ describe "File.basename" do end it "raises an ArgumentError if passed more than two arguments" do - -> { File.basename('bar.txt', '.txt', '.txt') }.should raise_error(ArgumentError) + -> { File.basename('bar.txt', '.txt', '.txt') }.should.raise(ArgumentError) end # specific to MS Windows @@ -151,8 +151,30 @@ describe "File.basename" do File.basename("c:\\bar.txt", ".*").should == "bar" File.basename("c:\\bar.txt.exe", ".*").should == "bar.txt" end + + it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do + # dir\fileソname.txt + path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS) + path.valid_encoding?.should == true + File.basename(path).should == "file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS) + end + end + + it "rejects strings encoded with non ASCII-compatible encodings" do + Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc| + path = "/foo/bar".encode(enc) + + -> { + File.basename(path) + }.should.raise(Encoding::CompatibilityError) + end end + it "works with all ASCII-compatible encodings" do + Encoding.list.select(&:ascii_compatible?).each do |enc| + File.basename("/foo/bar".encode(enc)).should == "bar".encode(enc) + end + end it "returns the extension for a multibyte filename" do File.basename('/path/Офис.m4a').should == "Офис.m4a" @@ -164,5 +186,20 @@ describe "File.basename" do basename.encoding.should == Encoding::Windows_1250 end + it "returns a new unfrozen String" do + exts = [nil, '.rb', '.*', '.txt'] + ['foo.rb','//', '/test/', 'test'].each do |example| + exts.each do |ext| + original = example.freeze + result = if ext + File.basename(original, ext) + else + File.basename(original) + end + result.should_not.equal?(original) + result.frozen?.should == false + end + end + end end diff --git a/spec/ruby/core/file/birthtime_spec.rb b/spec/ruby/core/file/birthtime_spec.rb index 755601df64..039fd7572c 100644 --- a/spec/ruby/core/file/birthtime_spec.rb +++ b/spec/ruby/core/file/birthtime_spec.rb @@ -1,60 +1,56 @@ require_relative '../../spec_helper' -describe "File.birthtime" do - before :each do - @file = __FILE__ - end +platform_is :windows, :darwin, :freebsd, :netbsd, :linux do + not_implemented_messages = [ + "birthtime() function is unimplemented", # unsupported OS/version + "birthtime is unimplemented", # unsupported filesystem + ] + + describe "File.birthtime" do + before :each do + @file = __FILE__ + end - after :each do - @file = nil - end + after :each do + @file = nil + end - platform_is :windows, :darwin, :freebsd, :netbsd do it "returns the birth time for the named file as a Time object" do File.birthtime(@file) - File.birthtime(@file).should be_kind_of(Time) + File.birthtime(@file).should.is_a?(Time) + rescue NotImplementedError => e + e.message.should.start_with?(*not_implemented_messages) end it "accepts an object that has a #to_path method" do + File.birthtime(@file) # Avoid to failure of mock object with old Kernel and glibc File.birthtime(mock_to_path(@file)) + rescue NotImplementedError => e + e.message.should.start_with?(*not_implemented_messages) end it "raises an Errno::ENOENT exception if the file is not found" do - -> { File.birthtime('bogus') }.should raise_error(Errno::ENOENT) + -> { File.birthtime('bogus') }.should.raise(Errno::ENOENT) + rescue NotImplementedError => e + e.message.should.start_with?(*not_implemented_messages) end end - platform_is :openbsd do - it "raises an NotImplementedError" do - -> { File.birthtime(@file) }.should raise_error(NotImplementedError) + describe "File#birthtime" do + before :each do + @file = File.open(__FILE__) end - end - - # TODO: depends on Linux kernel version -end -describe "File#birthtime" do - before :each do - @file = File.open(__FILE__) - end - - after :each do - @file.close - @file = nil - end + after :each do + @file.close + @file = nil + end - platform_is :windows, :darwin, :freebsd, :netbsd do it "returns the birth time for self" do @file.birthtime - @file.birthtime.should be_kind_of(Time) + @file.birthtime.should.is_a?(Time) + rescue NotImplementedError => e + e.message.should.start_with?(*not_implemented_messages) end end - - platform_is :openbsd do - it "raises an NotImplementedError" do - -> { @file.birthtime }.should raise_error(NotImplementedError) - end - end - - # TODO: depends on Linux kernel version end diff --git a/spec/ruby/core/file/chmod_spec.rb b/spec/ruby/core/file/chmod_spec.rb index 5ca15c9748..e0fd10ceb1 100644 --- a/spec/ruby/core/file/chmod_spec.rb +++ b/spec/ruby/core/file/chmod_spec.rb @@ -16,8 +16,8 @@ describe "File#chmod" do end it "raises RangeError with too large values" do - -> { @file.chmod(2**64) }.should raise_error(RangeError) - -> { @file.chmod(-2**63 - 1) }.should raise_error(RangeError) + -> { @file.chmod(2**64) }.should.raise(RangeError) + -> { @file.chmod(-2**63 - 1) }.should.raise(RangeError) end it "invokes to_int on non-integer argument" do @@ -97,8 +97,8 @@ describe "File.chmod" do end it "raises RangeError with too large values" do - -> { File.chmod(2**64, @file) }.should raise_error(RangeError) - -> { File.chmod(-2**63 - 1, @file) }.should raise_error(RangeError) + -> { File.chmod(2**64, @file) }.should.raise(RangeError) + -> { File.chmod(-2**63 - 1, @file) }.should.raise(RangeError) end it "accepts an object that has a #to_path method" do @@ -106,13 +106,13 @@ describe "File.chmod" do end it "throws a TypeError if the given path is not coercible into a string" do - -> { File.chmod(0, []) }.should raise_error(TypeError) + -> { File.chmod(0, []) }.should.raise(TypeError) end it "raises an error for a non existent path" do -> { File.chmod(0644, "#{@file}.not.existing") - }.should raise_error(Errno::ENOENT) + }.should.raise(Errno::ENOENT) end it "invokes to_int on non-integer argument" do diff --git a/spec/ruby/core/file/chown_spec.rb b/spec/ruby/core/file/chown_spec.rb index 8cc8f0d04b..3353aafc70 100644 --- a/spec/ruby/core/file/chown_spec.rb +++ b/spec/ruby/core/file/chown_spec.rb @@ -68,7 +68,7 @@ describe "File.chown" do it "raises an error for a non existent path" do -> { File.chown(nil, nil, "#{@fname}_not_existing") - }.should raise_error(Errno::ENOENT) + }.should.raise(Errno::ENOENT) end end @@ -78,15 +78,15 @@ describe "File.chown" do end describe "File#chown" do - before :each do - @fname = tmp('file_chown_test') - @file = File.open(@fname, 'w') - end + before :each do + @fname = tmp('file_chown_test') + @file = File.open(@fname, 'w') + end - after :each do - @file.close unless @file.closed? - rm_r @fname - end + after :each do + @file.close unless @file.closed? + rm_r @fname + end as_superuser do platform_is :windows do diff --git a/spec/ruby/core/file/constants/constants_spec.rb b/spec/ruby/core/file/constants/constants_spec.rb index 86946822c5..9d9c1c3b25 100644 --- a/spec/ruby/core/file/constants/constants_spec.rb +++ b/spec/ruby/core/file/constants/constants_spec.rb @@ -4,10 +4,10 @@ require_relative '../../../spec_helper' "FNM_DOTMATCH", "FNM_EXTGLOB", "FNM_NOESCAPE", "FNM_PATHNAME", "FNM_SYSCASE", "LOCK_EX", "LOCK_NB", "LOCK_SH", "LOCK_UN", "NONBLOCK", "RDONLY", - "RDWR", "TRUNC", "WRONLY"].each do |const| + "RDWR", "TRUNC", "WRONLY", "SHARE_DELETE"].each do |const| describe "File::Constants::#{const}" do it "is defined" do - File::Constants.const_defined?(const).should be_true + File::Constants.const_defined?(const).should == true end end end @@ -15,7 +15,7 @@ end platform_is :windows do describe "File::Constants::BINARY" do it "is defined" do - File::Constants.const_defined?(:BINARY).should be_true + File::Constants.const_defined?(:BINARY).should == true end end end @@ -24,7 +24,7 @@ platform_is_not :windows do ["NOCTTY", "SYNC"].each do |const| describe "File::Constants::#{const}" do it "is defined" do - File::Constants.const_defined?(const).should be_true + File::Constants.const_defined?(const).should == true end end end diff --git a/spec/ruby/core/file/ctime_spec.rb b/spec/ruby/core/file/ctime_spec.rb index 68a9fa43cb..cf37d1f4ee 100644 --- a/spec/ruby/core/file/ctime_spec.rb +++ b/spec/ruby/core/file/ctime_spec.rb @@ -11,17 +11,20 @@ describe "File.ctime" do it "returns the change time for the named file (the time at which directory information about the file was changed, not the file itself)." do File.ctime(@file) - File.ctime(@file).should be_kind_of(Time) + File.ctime(@file).should.is_a?(Time) end - guard -> { platform_is :linux or (platform_is :windows and ruby_version_is '2.5') } do + platform_is :linux, :windows do it "returns the change time for the named file (the time at which directory information about the file was changed, not the file itself) with microseconds." do - supports_subseconds = Integer(`stat -c%z '#{__FILE__}'`[/\.(\d+)/, 1], 10) + supports_subseconds = Integer(`stat -c%z '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10) if supports_subseconds != 0 File.ctime(__FILE__).usec.should > 0 else File.ctime(__FILE__).usec.should == 0 end + rescue Errno::ENOENT => e + # Windows don't have stat command. + skip e.message end end @@ -30,7 +33,7 @@ describe "File.ctime" do end it "raises an Errno::ENOENT exception if the file is not found" do - -> { File.ctime('bogus') }.should raise_error(Errno::ENOENT) + -> { File.ctime('bogus') }.should.raise(Errno::ENOENT) end end @@ -46,6 +49,6 @@ describe "File#ctime" do it "returns the change time for the named file (the time at which directory information about the file was changed, not the file itself)." do @file.ctime - @file.ctime.should be_kind_of(Time) + @file.ctime.should.is_a?(Time) end end diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb index 2ef04a7b64..855148a684 100644 --- a/spec/ruby/core/file/dirname_spec.rb +++ b/spec/ruby/core/file/dirname_spec.rb @@ -11,8 +11,37 @@ describe "File.dirname" do File.dirname('/foo/foo').should == '/foo' end + context "when level is passed" do + it "returns all the components of filename except the last parts by the level" do + File.dirname('/home/jason', 2).should == '/' + File.dirname('/home/jason/poot.txt', 2).should == '/home' + end + + it "returns the same String if the level is 0" do + File.dirname('poot.txt', 0).should == 'poot.txt' + File.dirname('/', 0).should == '/' + end + + it "raises ArgumentError if the level is negative" do + -> { + File.dirname('/home/jason', -1) + }.should.raise(ArgumentError, "negative level: -1") + end + + it "returns '/' when level exceeds the number of segments in the path" do + File.dirname("/home/jason", 100).should == '/' + end + + it "calls #to_int if passed not numeric value" do + object = Object.new + def object.to_int; 2; end + + File.dirname("/a/b/c/d", object).should == '/a/b' + end + end + it "returns a String" do - File.dirname("foo").should be_kind_of(String) + File.dirname("foo").should.is_a?(String) end it "does not modify its argument" do @@ -34,22 +63,48 @@ describe "File.dirname" do end it "returns all the components of filename except the last one (edge cases on all platforms)" do - File.dirname("").should == "." - File.dirname(".").should == "." - File.dirname("./").should == "." - File.dirname("./b/./").should == "./b" - File.dirname("..").should == "." - File.dirname("../").should == "." - File.dirname("/").should == "/" - File.dirname("/.").should == "/" - File.dirname("/foo/").should == "/" - File.dirname("/foo/.").should == "/foo" - File.dirname("/foo/./").should == "/foo" - File.dirname("/foo/../.").should == "/foo/.." - File.dirname("foo/../").should == "foo" + File.dirname("").should == "." + File.dirname(".").should == "." + File.dirname("./").should == "." + File.dirname("./b/./").should == "./b" + File.dirname("..").should == "." + File.dirname("../").should == "." + File.dirname("/").should == "/" + File.dirname("/.").should == "/" + File.dirname("/foo/").should == "/" + File.dirname("/foo/.").should == "/foo" + File.dirname("/foo/./").should == "/foo" + File.dirname("/foo/../.").should == "/foo/.." + File.dirname("foo/../").should == "foo" + end + + it "rejects strings encoded with non ASCII-compatible encodings" do + Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc| + path = "/foo/bar".encode(enc) + -> { + File.dirname(path) + }.should.raise(Encoding::CompatibilityError) + end + end + + it "works with all ASCII-compatible encodings" do + Encoding.list.select(&:ascii_compatible?).each do |enc| + File.dirname("/foo/bar".encode(enc)).should == "/foo".encode(enc) + end + end + + it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do + # dir/fileソname.txt + path = "dir/file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS) + path.valid_encoding?.should == true + File.dirname(path).should == "dir" end platform_is_not :windows do + it "ignores repeated leading / (edge cases on non-windows)" do + File.dirname("/////foo/bar/").should == "/foo" + end + it "returns all the components of filename except the last one (edge cases on non-windows)" do File.dirname('/////').should == '/' File.dirname("//foo//").should == "/" @@ -65,6 +120,13 @@ describe "File.dirname" do File.dirname("//foo//").should == "//foo" File.dirname('/////').should == '//' end + + it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence (windows)" do + # dir\fileソname.txt + path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS) + path.valid_encoding?.should == true + File.dirname(path).should == "dir" + end end it "accepts an object that has a #to_path method" do @@ -72,10 +134,10 @@ describe "File.dirname" do end it "raises a TypeError if not passed a String type" do - -> { File.dirname(nil) }.should raise_error(TypeError) - -> { File.dirname(0) }.should raise_error(TypeError) - -> { File.dirname(true) }.should raise_error(TypeError) - -> { File.dirname(false) }.should raise_error(TypeError) + -> { File.dirname(nil) }.should.raise(TypeError) + -> { File.dirname(0) }.should.raise(TypeError) + -> { File.dirname(true) }.should.raise(TypeError) + -> { File.dirname(false) }.should.raise(TypeError) end # Windows specific tests diff --git a/spec/ruby/core/file/empty_spec.rb b/spec/ruby/core/file/empty_spec.rb index 77f132303e..e8c9941676 100644 --- a/spec/ruby/core/file/empty_spec.rb +++ b/spec/ruby/core/file/empty_spec.rb @@ -4,10 +4,4 @@ require_relative '../../shared/file/zero' describe "File.empty?" do it_behaves_like :file_zero, :empty?, File it_behaves_like :file_zero_missing, :empty?, File - - platform_is :solaris do - it "returns false for /dev/null" do - File.empty?('/dev/null').should == true - end - end end diff --git a/spec/ruby/core/file/exist_spec.rb b/spec/ruby/core/file/exist_spec.rb index ddb5febcba..b5600e5b07 100644 --- a/spec/ruby/core/file/exist_spec.rb +++ b/spec/ruby/core/file/exist_spec.rb @@ -4,3 +4,9 @@ require_relative '../../shared/file/exist' describe "File.exist?" do it_behaves_like :file_exist, :exist?, File end + +describe "File.exists?" do + it "has been removed" do + File.should_not.respond_to?(:exists?) + end +end diff --git a/spec/ruby/core/file/exists_spec.rb b/spec/ruby/core/file/exists_spec.rb deleted file mode 100644 index 31d0e4dd1e..0000000000 --- a/spec/ruby/core/file/exists_spec.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative '../../spec_helper' -require_relative '../../shared/file/exist' - -describe "File.exists?" do - it_behaves_like :file_exist, :exists?, File -end diff --git a/spec/ruby/core/file/expand_path_spec.rb b/spec/ruby/core/file/expand_path_spec.rb index 88078645ab..160494f145 100644 --- a/spec/ruby/core/file/expand_path_spec.rb +++ b/spec/ruby/core/file/expand_path_spec.rb @@ -92,7 +92,7 @@ describe "File.expand_path" do end it "raises an ArgumentError if the path is not valid" do - -> { File.expand_path("~a_not_existing_user") }.should raise_error(ArgumentError) + -> { File.expand_path("~a_not_existing_user") }.should.raise(ArgumentError) end it "expands ~ENV['USER'] to the user's home directory" do @@ -117,9 +117,9 @@ describe "File.expand_path" do end it "raises a TypeError if not passed a String type" do - -> { File.expand_path(1) }.should raise_error(TypeError) - -> { File.expand_path(nil) }.should raise_error(TypeError) - -> { File.expand_path(true) }.should raise_error(TypeError) + -> { File.expand_path(1) }.should.raise(TypeError) + -> { File.expand_path(nil) }.should.raise(TypeError) + -> { File.expand_path(true) }.should.raise(TypeError) end platform_is_not :windows do @@ -137,11 +137,11 @@ describe "File.expand_path" do it "returns a String in the same encoding as the argument" do Encoding.default_external = Encoding::SHIFT_JIS - path = "./a".force_encoding Encoding::CP1251 - File.expand_path(path).encoding.should equal(Encoding::CP1251) + path = "./a".dup.force_encoding Encoding::CP1251 + File.expand_path(path).encoding.should.equal?(Encoding::CP1251) weird_path = [222, 173, 190, 175].pack('C*') - File.expand_path(weird_path).encoding.should equal(Encoding::BINARY) + File.expand_path(weird_path).encoding.should.equal?(Encoding::BINARY) end platform_is_not :windows do @@ -159,7 +159,7 @@ describe "File.expand_path" do platform_is_not :windows do it "raises an Encoding::CompatibilityError if the external encoding is not compatible" do Encoding.default_external = Encoding::UTF_16BE - -> { File.expand_path("./a") }.should raise_error(Encoding::CompatibilityError) + -> { File.expand_path("./a") }.should.raise(Encoding::CompatibilityError) end end @@ -179,7 +179,7 @@ describe "File.expand_path" do str = FileSpecs::SubString.new "./a/b/../c" path = File.expand_path(str, @base) path.should == "#{@base}/a/c" - path.should be_an_instance_of(String) + path.should.instance_of?(String) end end @@ -203,9 +203,9 @@ platform_is_not :windows do it "does not return a frozen string" do home = "/rubyspec_home" - File.expand_path('~').frozen?.should == false - File.expand_path('~', '/tmp/gumby/ddd').frozen?.should == false - File.expand_path('~/a', '/tmp/gumby/ddd').frozen?.should == false + File.expand_path('~').should_not.frozen? + File.expand_path('~', '/tmp/gumby/ddd').should_not.frozen? + File.expand_path('~/a', '/tmp/gumby/ddd').should_not.frozen? end end @@ -244,7 +244,7 @@ platform_is_not :windows do it "raises an ArgumentError when passed '~' if HOME == ''" do ENV["HOME"] = "" - -> { File.expand_path("~") }.should raise_error(ArgumentError) + -> { File.expand_path("~") }.should.raise(ArgumentError) end end @@ -259,7 +259,7 @@ platform_is_not :windows do it "raises an ArgumentError" do ENV["HOME"] = "non-absolute" - -> { File.expand_path("~") }.should raise_error(ArgumentError, 'non-absolute home') + -> { File.expand_path("~") }.should.raise(ArgumentError, 'non-absolute home') end end end diff --git a/spec/ruby/core/file/extname_spec.rb b/spec/ruby/core/file/extname_spec.rb index e9b53bc24d..995d0ea31a 100644 --- a/spec/ruby/core/file/extname_spec.rb +++ b/spec/ruby/core/file/extname_spec.rb @@ -12,6 +12,16 @@ describe "File.extname" do File.extname(".app.conf").should == ".conf" end + it "returns unfrozen strings" do + File.extname("foo.rb").frozen?.should == false + File.extname("/foo/bar.rb").frozen?.should == false + File.extname("/foo.rb/bar.c").frozen?.should == false + File.extname("bar").frozen?.should == false + File.extname(".bashrc").frozen?.should == false + File.extname("/foo.bar/baz").frozen?.should == false + File.extname(".app.conf").frozen?.should == false + end + it "returns the extension for edge cases" do File.extname("").should == "" File.extname(".").should == "" @@ -23,14 +33,14 @@ describe "File.extname" do end describe "for a filename ending with a dot" do - guard -> { platform_is :windows or ruby_version_is ""..."2.7" } do + platform_is :windows do it "returns ''" do File.extname(".foo.").should == "" File.extname("foo.").should == "" end end - guard -> { platform_is_not :windows and ruby_version_is "2.7" } do + platform_is_not :windows do it "returns '.'" do File.extname(".foo.").should == "." File.extname("foo.").should == "." @@ -47,15 +57,15 @@ describe "File.extname" do end it "raises a TypeError if not passed a String type" do - -> { File.extname(nil) }.should raise_error(TypeError) - -> { File.extname(0) }.should raise_error(TypeError) - -> { File.extname(true) }.should raise_error(TypeError) - -> { File.extname(false) }.should raise_error(TypeError) + -> { File.extname(nil) }.should.raise(TypeError) + -> { File.extname(0) }.should.raise(TypeError) + -> { File.extname(true) }.should.raise(TypeError) + -> { File.extname(false) }.should.raise(TypeError) end it "raises an ArgumentError if not passed one argument" do - -> { File.extname }.should raise_error(ArgumentError) - -> { File.extname("foo.bar", "foo.baz") }.should raise_error(ArgumentError) + -> { File.extname }.should.raise(ArgumentError) + -> { File.extname("foo.bar", "foo.baz") }.should.raise(ArgumentError) end diff --git a/spec/ruby/core/file/flock_spec.rb b/spec/ruby/core/file/flock_spec.rb index 751e99d994..23ddf89ed8 100644 --- a/spec/ruby/core/file/flock_spec.rb +++ b/spec/ruby/core/file/flock_spec.rb @@ -30,7 +30,7 @@ describe "File#flock" do it "returns false if trying to lock an exclusively locked file" do @file.flock File::LOCK_EX - ruby_exe(<<-END_OF_CODE, escape: true).should == "false" + ruby_exe(<<-END_OF_CODE).should == "false" File.open('#{@name}', "w") do |f2| print f2.flock(File::LOCK_EX | File::LOCK_NB).to_s end @@ -40,7 +40,7 @@ describe "File#flock" do it "blocks if trying to lock an exclusively locked file" do @file.flock File::LOCK_EX - out = ruby_exe(<<-END_OF_CODE, escape: true) + out = ruby_exe(<<-END_OF_CODE) running = false t = Thread.new do @@ -72,35 +72,3 @@ describe "File#flock" do end end end - -platform_is :solaris do - describe "File#flock on Solaris" do - before :each do - @name = tmp("flock_test") - touch(@name) - - @read_file = File.open @name, "r" - @write_file = File.open @name, "w" - end - - after :each do - @read_file.flock File::LOCK_UN - @read_file.close - @write_file.flock File::LOCK_UN - @write_file.close - rm_r @name - end - - it "fails with EBADF acquiring exclusive lock on read-only File" do - -> do - @read_file.flock File::LOCK_EX - end.should raise_error(Errno::EBADF) - end - - it "fails with EBADF acquiring shared lock on read-only File" do - -> do - @write_file.flock File::LOCK_SH - end.should raise_error(Errno::EBADF) - end - end -end diff --git a/spec/ruby/core/file/ftype_spec.rb b/spec/ruby/core/file/ftype_spec.rb index 8ff70baa80..ab9f76b79b 100644 --- a/spec/ruby/core/file/ftype_spec.rb +++ b/spec/ruby/core/file/ftype_spec.rb @@ -7,19 +7,19 @@ describe "File.ftype" do end it "raises ArgumentError if not given exactly one filename" do - -> { File.ftype }.should raise_error(ArgumentError) - -> { File.ftype('blah', 'bleh') }.should raise_error(ArgumentError) + -> { File.ftype }.should.raise(ArgumentError) + -> { File.ftype('blah', 'bleh') }.should.raise(ArgumentError) end it "raises Errno::ENOENT if the file is not valid" do -> { File.ftype("/#{$$}#{Time.now.to_f}") - }.should raise_error(Errno::ENOENT) + }.should.raise(Errno::ENOENT) end it "returns a String" do FileSpecs.normal_file do |file| - File.ftype(file).should be_kind_of(String) + File.ftype(file).should.is_a?(String) end end @@ -35,6 +35,14 @@ describe "File.ftype" do end end + it "uses to_path to convert arguments" do + FileSpecs.normal_file do |file| + obj = mock('path') + obj.should_receive(:to_path).and_return(file) + File.ftype(obj).should == 'file' + end + end + # Both FreeBSD and Windows does not have block devices platform_is_not :freebsd, :windows do with_block_device do diff --git a/spec/ruby/core/file/inspect_spec.rb b/spec/ruby/core/file/inspect_spec.rb index 148e789c62..fe87429e8d 100644 --- a/spec/ruby/core/file/inspect_spec.rb +++ b/spec/ruby/core/file/inspect_spec.rb @@ -12,6 +12,6 @@ describe "File#inspect" do end it "returns a String" do - @file.inspect.should be_an_instance_of(String) + @file.inspect.should.instance_of?(String) end end diff --git a/spec/ruby/core/file/join_spec.rb b/spec/ruby/core/file/join_spec.rb index f1eab02de0..0f0911ea31 100644 --- a/spec/ruby/core/file/join_spec.rb +++ b/spec/ruby/core/file/join_spec.rb @@ -52,7 +52,7 @@ describe "File.join" do it "returns a duplicate string when given a single argument" do str = "usr" File.join(str).should == str - File.join(str).should_not equal(str) + File.join(str).should_not.equal?(str) end it "supports any number of arguments" do @@ -104,15 +104,15 @@ describe "File.join" do it "raises an ArgumentError if passed a recursive array" do a = ["a"] a << a - -> { File.join a }.should raise_error(ArgumentError) + -> { File.join a }.should.raise(ArgumentError) end it "raises a TypeError exception when args are nil" do - -> { File.join nil }.should raise_error(TypeError) + -> { File.join nil }.should.raise(TypeError) end it "calls #to_str" do - -> { File.join(mock('x')) }.should raise_error(TypeError) + -> { File.join(mock('x')) }.should.raise(TypeError) bin = mock("bin") bin.should_receive(:to_str).exactly(:twice).and_return("bin") @@ -129,11 +129,20 @@ describe "File.join" do end it "calls #to_path" do - -> { File.join(mock('x')) }.should raise_error(TypeError) + -> { File.join(mock('x')) }.should.raise(TypeError) bin = mock("bin") bin.should_receive(:to_path).exactly(:twice).and_return("bin") File.join(bin).should == "bin" File.join("usr", bin).should == "usr/bin" end + + it "raises errors for null bytes" do + -> { File.join("\x00x", "metadata.gz") }.should.raise(ArgumentError) { |e| + e.message.should == 'string contains null byte' + } + -> { File.join("metadata.gz", "\x00x") }.should.raise(ArgumentError) { |e| + e.message.should == 'string contains null byte' + } + end end diff --git a/spec/ruby/core/file/lchmod_spec.rb b/spec/ruby/core/file/lchmod_spec.rb index 9490459a02..3c44374983 100644 --- a/spec/ruby/core/file/lchmod_spec.rb +++ b/spec/ruby/core/file/lchmod_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' describe "File.lchmod" do - platform_is_not :linux, :windows, :openbsd, :solaris, :aix do + platform_is_not :linux, :windows, :openbsd, :aix do before :each do @fname = tmp('file_chmod_test') @lname = @fname + '.lnk' @@ -20,23 +20,13 @@ describe "File.lchmod" do File.chmod(0222, @lname).should == 1 File.lchmod(0755, @lname).should == 1 - File.lstat(@lname).executable?.should == true - File.lstat(@lname).readable?.should == true - File.lstat(@lname).writable?.should == true + File.lstat(@lname).should.executable? + File.lstat(@lname).should.readable? + File.lstat(@lname).should.writable? - File.stat(@lname).executable?.should == false - File.stat(@lname).readable?.should == false - File.stat(@lname).writable?.should == true - end - end - - platform_is :linux, :openbsd, :aix do - it "returns false from #respond_to?" do - File.respond_to?(:lchmod).should be_false - end - - it "raises a NotImplementedError when called" do - -> { File.lchmod 0 }.should raise_error(NotImplementedError) + File.stat(@lname).should_not.executable? + File.stat(@lname).should_not.readable? + File.stat(@lname).should.writable? end end end diff --git a/spec/ruby/core/file/link_spec.rb b/spec/ruby/core/file/link_spec.rb index cc63c76aa3..768ee4b0fa 100644 --- a/spec/ruby/core/file/link_spec.rb +++ b/spec/ruby/core/file/link_spec.rb @@ -13,7 +13,7 @@ describe "File.link" do rm_r @link, @file end - platform_is_not :windows do + platform_is_not :windows, :android do it "link a file with another" do File.link(@file, @link).should == 0 File.should.exist?(@link) @@ -22,18 +22,18 @@ describe "File.link" do it "raises an Errno::EEXIST if the target already exists" do File.link(@file, @link) - -> { File.link(@file, @link) }.should raise_error(Errno::EEXIST) + -> { File.link(@file, @link) }.should.raise(Errno::EEXIST) end it "raises an ArgumentError if not passed two arguments" do - -> { File.link }.should raise_error(ArgumentError) - -> { File.link(@file) }.should raise_error(ArgumentError) - -> { File.link(@file, @link, @file) }.should raise_error(ArgumentError) + -> { File.link }.should.raise(ArgumentError) + -> { File.link(@file) }.should.raise(ArgumentError) + -> { File.link(@file, @link, @file) }.should.raise(ArgumentError) end it "raises a TypeError if not passed String types" do - -> { File.link(@file, nil) }.should raise_error(TypeError) - -> { File.link(@file, 1) }.should raise_error(TypeError) + -> { File.link(@file, nil) }.should.raise(TypeError) + -> { File.link(@file, 1) }.should.raise(TypeError) end end end diff --git a/spec/ruby/core/file/lstat_spec.rb b/spec/ruby/core/file/lstat_spec.rb index 918ed02163..a5ea9d15a5 100644 --- a/spec/ruby/core/file/lstat_spec.rb +++ b/spec/ruby/core/file/lstat_spec.rb @@ -22,8 +22,8 @@ describe "File.lstat" do it "returns a File::Stat object with symlink properties for a symlink" do st = File.lstat(@link) - st.symlink?.should == true - st.file?.should == false + st.should.symlink? + st.should_not.file? end end end diff --git a/spec/ruby/core/file/lutime_spec.rb b/spec/ruby/core/file/lutime_spec.rb index 7449bc4389..0f6df42ea3 100644 --- a/spec/ruby/core/file/lutime_spec.rb +++ b/spec/ruby/core/file/lutime_spec.rb @@ -1,40 +1,43 @@ require_relative '../../spec_helper' +require_relative 'shared/update_time' -ruby_version_is "2.5" do +platform_is_not :windows do describe "File.lutime" do - platform_is_not :windows do - before :each do - @atime = Time.utc(2000) - @mtime = Time.utc(2001) - @file = tmp("specs_lutime_file") - @symlink = tmp("specs_lutime_symlink") - touch @file - File.symlink(@file, @symlink) - end + it_behaves_like :update_time, :lutime + end + + describe "File.lutime" do + before :each do + @atime = Time.utc(2000) + @mtime = Time.utc(2001) + @file = tmp("specs_lutime_file") + @symlink = tmp("specs_lutime_symlink") + touch @file + File.symlink(@file, @symlink) + end - after :each do - rm_r @file, @symlink - end + after :each do + rm_r @file, @symlink + end - it "sets the access and modification time for a regular file" do - File.lutime(@atime, @mtime, @file) - stat = File.stat(@file) - stat.atime.should == @atime - stat.mtime.should === @mtime - end + it "sets the access and modification time for a regular file" do + File.lutime(@atime, @mtime, @file) + stat = File.stat(@file) + stat.atime.should == @atime + stat.mtime.should === @mtime + end - it "sets the access and modification time for a symlink" do - original = File.stat(@file) + it "sets the access and modification time for a symlink" do + original = File.stat(@file) - File.lutime(@atime, @mtime, @symlink) - stat = File.lstat(@symlink) - stat.atime.should == @atime - stat.mtime.should === @mtime + File.lutime(@atime, @mtime, @symlink) + stat = File.lstat(@symlink) + stat.atime.should == @atime + stat.mtime.should === @mtime - file = File.stat(@file) - file.atime.should == original.atime - file.mtime.should == original.mtime - end + file = File.stat(@file) + file.atime.should == original.atime + file.mtime.should == original.mtime end end end diff --git a/spec/ruby/core/file/mkfifo_spec.rb b/spec/ruby/core/file/mkfifo_spec.rb index 19298c967c..ce4a67fe31 100644 --- a/spec/ruby/core/file/mkfifo_spec.rb +++ b/spec/ruby/core/file/mkfifo_spec.rb @@ -19,13 +19,13 @@ describe "File.mkfifo" do context "when path passed is not a String value" do it "raises a TypeError" do - -> { File.mkfifo(:"/tmp/fifo") }.should raise_error(TypeError) + -> { File.mkfifo(:"/tmp/fifo") }.should.raise(TypeError) end end context "when path does not exist" do it "raises an Errno::ENOENT exception" do - -> { File.mkfifo("/bogus/path") }.should raise_error(Errno::ENOENT) + -> { File.mkfifo("/bogus/path") }.should.raise(Errno::ENOENT) end end diff --git a/spec/ruby/core/file/mtime_spec.rb b/spec/ruby/core/file/mtime_spec.rb index 1941e2ff85..d83725e25d 100644 --- a/spec/ruby/core/file/mtime_spec.rb +++ b/spec/ruby/core/file/mtime_spec.rb @@ -11,25 +11,30 @@ describe "File.mtime" do end it "returns the modification Time of the file" do - File.mtime(@filename).should be_kind_of(Time) + File.mtime(@filename).should.is_a?(Time) File.mtime(@filename).should be_close(@mtime, TIME_TOLERANCE) end - guard -> { platform_is :linux or (platform_is :windows and ruby_version_is '2.5') } do - it "returns the modification Time of the file with microseconds" do - supports_subseconds = Integer(`stat -c%y '#{__FILE__}'`[/\.(\d+)/, 1], 10) - if supports_subseconds != 0 - expected_time = Time.at(Time.now.to_i + 0.123456) - File.utime 0, expected_time, @filename - File.mtime(@filename).usec.should == expected_time.usec - else - File.mtime(__FILE__).usec.should == 0 + platform_is :linux, :windows do + unless ENV.key?('TRAVIS') # https://bugs.ruby-lang.org/issues/17926 + it "returns the modification Time of the file with microseconds" do + supports_subseconds = Integer(`stat -c%y '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10) + if supports_subseconds != 0 + expected_time = Time.at(Time.now.to_i + 0.123456) + File.utime 0, expected_time, @filename + File.mtime(@filename).usec.should == expected_time.usec + else + File.mtime(__FILE__).usec.should == 0 + end + rescue Errno::ENOENT => e + # Windows don't have stat command. + skip e.message end end end it "raises an Errno::ENOENT exception if the file is not found" do - -> { File.mtime('bogus') }.should raise_error(Errno::ENOENT) + -> { File.mtime('bogus') }.should.raise(Errno::ENOENT) end end @@ -45,7 +50,7 @@ describe "File#mtime" do end it "returns the modification Time of the file" do - @f.mtime.should be_kind_of(Time) + @f.mtime.should.is_a?(Time) end end diff --git a/spec/ruby/core/file/new_spec.rb b/spec/ruby/core/file/new_spec.rb index 004f78503a..4cd2cb5dcb 100644 --- a/spec/ruby/core/file/new_spec.rb +++ b/spec/ruby/core/file/new_spec.rb @@ -16,13 +16,13 @@ describe "File.new" do it "returns a new File with mode string" do @fh = File.new(@file, 'w') - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end it "returns a new File with mode num" do @fh = File.new(@file, @flags) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end @@ -30,7 +30,7 @@ describe "File.new" do rm_r @file File.umask(0011) @fh = File.new(@file, @flags, 0755) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) platform_is_not :windows do File.stat(@file).mode.to_s(8).should == "100744" end @@ -44,7 +44,7 @@ describe "File.new" do rm_r @file begin f = File.new(@file, "w", 0444) - -> { f.puts("test") }.should_not raise_error(IOError) + -> { f.puts("test") }.should_not.raise(IOError) ensure f.close end @@ -74,49 +74,84 @@ describe "File.new" do @fh = File.new(@file) fh_copy = File.new(@fh.fileno) fh_copy.autoclose = false - fh_copy.should be_kind_of(File) + fh_copy.should.is_a?(File) + File.should.exist?(@file) + end + + it "returns a new read-only File when mode is not specified" do + @fh = File.new(@file) + + -> { @fh.puts("test") }.should.raise(IOError) + @fh.read.should == "" + File.should.exist?(@file) + end + + it "returns a new read-only File when mode is not specified but flags option is present" do + @fh = File.new(@file, flags: File::CREAT) + + -> { @fh.puts("test") }.should.raise(IOError) + @fh.read.should == "" File.should.exist?(@file) end it "creates a new file when use File::EXCL mode" do @fh = File.new(@file, File::EXCL) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end - it "raises an Errorno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do - -> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should raise_error(Errno::EEXIST) + it "raises an Errno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do + -> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should.raise(Errno::EEXIST) end it "creates a new file when use File::WRONLY|File::APPEND mode" do @fh = File.new(@file, File::WRONLY|File::APPEND) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end it "returns a new File when use File::APPEND mode" do @fh = File.new(@file, File::APPEND) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end it "returns a new File when use File::RDONLY|File::APPEND mode" do @fh = File.new(@file, File::RDONLY|File::APPEND) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end it "returns a new File when use File::RDONLY|File::WRONLY mode" do @fh = File.new(@file, File::RDONLY|File::WRONLY) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end - it "creates a new file when use File::WRONLY|File::TRUNC mode" do @fh = File.new(@file, File::WRONLY|File::TRUNC) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) + File.should.exist?(@file) + end + + it "returns a new read-only File when use File::RDONLY|File::CREAT mode" do + @fh = File.new(@file, File::RDONLY|File::CREAT) + @fh.should.is_a?(File) File.should.exist?(@file) + + # it's read-only + -> { @fh.puts("test") }.should.raise(IOError) + @fh.read.should == "" + end + + it "returns a new read-only File when use File::CREAT mode" do + @fh = File.new(@file, File::CREAT) + @fh.should.is_a?(File) + File.should.exist?(@file) + + # it's read-only + -> { @fh.puts("test") }.should.raise(IOError) + @fh.read.should == "" end it "coerces filename using to_str" do @@ -133,17 +168,43 @@ describe "File.new" do File.should.exist?(@file) end + it "accepts options as a keyword argument" do + @fh = File.new(@file, 'w', 0755, flags: @flags) + @fh.should.is_a?(File) + @fh.close + + -> { + @fh = File.new(@file, 'w', 0755, {flags: @flags}) + }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") + end + + it "bitwise-ORs mode and flags option" do + -> { + @fh = File.new(@file, 'w', flags: File::EXCL) + }.should.raise(Errno::EEXIST, /File exists/) + + -> { + @fh = File.new(@file, mode: 'w', flags: File::EXCL) + }.should.raise(Errno::EEXIST, /File exists/) + end + + it "does not use the given block and warns to use File::open" do + -> { + @fh = File.new(@file) { raise } + }.should complain(/warning: File::new\(\) does not take block; use File::open\(\) instead/) + end + it "raises a TypeError if the first parameter can't be coerced to a string" do - -> { File.new(true) }.should raise_error(TypeError) - -> { File.new(false) }.should raise_error(TypeError) + -> { File.new(true) }.should.raise(TypeError) + -> { File.new(false) }.should.raise(TypeError) end it "raises a TypeError if the first parameter is nil" do - -> { File.new(nil) }.should raise_error(TypeError) + -> { File.new(nil) }.should.raise(TypeError) end it "raises an Errno::EBADF if the first parameter is an invalid file descriptor" do - -> { File.new(-1) }.should raise_error(Errno::EBADF) + -> { File.new(-1) }.should.raise(Errno::EBADF) end platform_is_not :windows do @@ -152,7 +213,7 @@ describe "File.new" do -> { f = File.new(@fh.fileno, @flags) f.autoclose = false - }.should raise_error(Errno::EINVAL) + }.should.raise(Errno::EINVAL) end end diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb index e3c5618795..7318c31636 100644 --- a/spec/ruby/core/file/open_spec.rb +++ b/spec/ruby/core/file/open_spec.rb @@ -28,7 +28,7 @@ describe "File.open" do 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 } - @fh.closed?.should == true + @fh.should.closed? end it "invokes close on an opened file when exiting the block" do @@ -40,7 +40,7 @@ describe "File.open" do it "propagates non-StandardErrors produced by close" do -> { File.open(@file, 'r') { |f| FileSpecs.make_closer f, Exception } - }.should raise_error(Exception) + }.should.raise(Exception) ScratchPad.recorded.should == [:file_opened, :file_closed] end @@ -48,7 +48,7 @@ describe "File.open" do it "propagates StandardErrors produced by close" do -> { File.open(@file, 'r') { |f| FileSpecs.make_closer f, StandardError } - }.should raise_error(StandardError) + }.should.raise(StandardError) ScratchPad.recorded.should == [:file_opened, :file_closed] end @@ -62,13 +62,13 @@ describe "File.open" do it "opens the file (basic case)" do @fh = File.open(@file) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end it "opens the file with unicode characters" do @fh = File.open(@unicode_path, "w") - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@unicode_path) end @@ -79,7 +79,7 @@ describe "File.open" do it "opens with mode string" do @fh = File.open(@file, 'w') - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end @@ -90,7 +90,7 @@ describe "File.open" do it "opens a file with mode num" do @fh = File.open(@file, @flags) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end @@ -101,7 +101,7 @@ describe "File.open" do it "opens a file with mode and permission as nil" do @fh = File.open(@file, nil, nil) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) end # For this test we delete the file first to reset the perms @@ -109,7 +109,7 @@ describe "File.open" do rm_r @file File.umask(0011) @fh = File.open(@file, @flags, 0755) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) platform_is_not :windows do @fh.lstat.mode.to_s(8).should == "100744" end @@ -161,69 +161,69 @@ describe "File.open" do @fh = File.open(@file) fh_copy = File.open(@fh.fileno) fh_copy.autoclose = false - fh_copy.should be_kind_of(File) + fh_copy.should.is_a?(File) File.should.exist?(@file) end it "opens a file that no exists when use File::WRONLY mode" do - -> { File.open(@nonexistent, File::WRONLY) }.should raise_error(Errno::ENOENT) + -> { File.open(@nonexistent, File::WRONLY) }.should.raise(Errno::ENOENT) end it "opens a file that no exists when use File::RDONLY mode" do - -> { File.open(@nonexistent, File::RDONLY) }.should raise_error(Errno::ENOENT) + -> { File.open(@nonexistent, File::RDONLY) }.should.raise(Errno::ENOENT) end it "opens a file that no exists when use 'r' mode" do - -> { File.open(@nonexistent, 'r') }.should raise_error(Errno::ENOENT) + -> { File.open(@nonexistent, 'r') }.should.raise(Errno::ENOENT) end it "opens a file that no exists when use File::EXCL mode" do - -> { File.open(@nonexistent, File::EXCL) }.should raise_error(Errno::ENOENT) + -> { File.open(@nonexistent, File::EXCL) }.should.raise(Errno::ENOENT) end it "opens a file that no exists when use File::NONBLOCK mode" do - -> { File.open(@nonexistent, File::NONBLOCK) }.should raise_error(Errno::ENOENT) + -> { File.open(@nonexistent, File::NONBLOCK) }.should.raise(Errno::ENOENT) end platform_is_not :openbsd, :windows do it "opens a file that no exists when use File::TRUNC mode" do - -> { File.open(@nonexistent, File::TRUNC) }.should raise_error(Errno::ENOENT) + -> { File.open(@nonexistent, File::TRUNC) }.should.raise(Errno::ENOENT) end end platform_is :openbsd, :windows do it "does not open a file that does no exists when using File::TRUNC mode" do - -> { File.open(@nonexistent, File::TRUNC) }.should raise_error(Errno::EINVAL) + -> { File.open(@nonexistent, File::TRUNC) }.should.raise(Errno::EINVAL) end end platform_is_not :windows do it "opens a file that no exists when use File::NOCTTY mode" do - -> { File.open(@nonexistent, File::NOCTTY) }.should raise_error(Errno::ENOENT) + -> { File.open(@nonexistent, File::NOCTTY) }.should.raise(Errno::ENOENT) 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) + @fh.should.is_a?(File) File.should.exist?(@file) 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) + @fh.should.is_a?(File) File.should.exist?(@file) 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) + @fh.should.is_a?(File) File.should.exist?(@file) end # Check the grants associated to the different open modes combinations. it "raises an ArgumentError exception when call with an unknown mode" do - -> { File.open(@file, "q") }.should raise_error(ArgumentError) + -> { File.open(@file, "q") }.should.raise(ArgumentError) end it "can read in a block when call open with RDONLY mode" do @@ -240,13 +240,13 @@ describe "File.open" do it "raises an IO exception when write in a block opened with RDONLY mode" do File.open(@file, File::RDONLY) do |f| - -> { f.puts "writing ..." }.should raise_error(IOError) + -> { f.puts "writing ..." }.should.raise(IOError) end end it "raises an IO exception when write in a block opened with 'r' mode" do File.open(@file, "r") do |f| - -> { f.puts "writing ..." }.should raise_error(IOError) + -> { f.puts "writing ..." }.should.raise(IOError) end end @@ -261,7 +261,7 @@ describe "File.open" do File.open(@file, File::WRONLY|File::RDONLY ) do |f| f.gets.should == nil end - }.should raise_error(IOError) + }.should.raise(IOError) end it "can write in a block when call open with WRONLY mode" do @@ -278,48 +278,48 @@ describe "File.open" do it "raises an IOError when read in a block opened with WRONLY mode" do File.open(@file, File::WRONLY) do |f| - -> { f.gets }.should raise_error(IOError) + -> { f.gets }.should.raise(IOError) end end it "raises an IOError when read in a block opened with 'w' mode" do File.open(@file, "w") do |f| - -> { f.gets }.should raise_error(IOError) + -> { f.gets }.should.raise(IOError) end end it "raises an IOError when read in a block opened with 'a' mode" do File.open(@file, "a") do |f| - -> { f.gets }.should raise_error(IOError) + -> { f.gets }.should.raise(IOError) 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 - -> { f.gets }.should raise_error(IOError) + -> { f.gets }.should.raise(IOError) 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| - -> { f.gets }.should raise_error(IOError) + -> { f.gets }.should.raise(IOError) 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 - -> { f.gets }.should raise_error(IOError) + -> { f.gets }.should.raise(IOError) end end - it "raises an IOError when read in a block opened with File::RDONLY|File::APPEND mode" do + it "raises an IOError when write in a block opened with File::RDONLY|File::APPEND mode" do -> { File.open(@file, File::RDONLY|File::APPEND ) do |f| f.puts("writing") end - }.should raise_error(IOError) + }.should.raise(IOError) end it "can read and write in a block when call open with RDWR mode" do @@ -336,7 +336,7 @@ describe "File.open" do File.open(@file, File::EXCL) do |f| f.puts("writing").should == nil end - }.should raise_error(IOError) + }.should.raise(IOError) end it "can read in a block when call open with File::EXCL mode" do @@ -354,17 +354,17 @@ describe "File.open" do end end - it "raises an Errorno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do + it "raises an Errno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do -> { File.open(@file, File::CREAT|File::EXCL) do |f| f.puts("writing") end - }.should raise_error(Errno::EEXIST) + }.should.raise(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) + @fh.should.is_a?(File) File.should.exist?(@file) end @@ -386,7 +386,7 @@ describe "File.open" do File.open(@file, File::RDONLY|File::APPEND) do |f| f.puts("writing").should == nil end - }.should raise_error(IOError) + }.should.raise(IOError) end platform_is_not :openbsd, :windows do @@ -407,7 +407,7 @@ describe "File.open" do fh1 = File.open(@file, "w") begin @fh = File.open(@file, File::WRONLY|File::TRUNC) - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) ensure fh1.close @@ -420,15 +420,15 @@ describe "File.open" do File.open(@file, File::TRUNC) do |f| f.puts("writing") end - }.should raise_error(IOError) + }.should.raise(IOError) end - it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do + it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do -> { File.open(@file, File::RDONLY|File::TRUNC) do |f| f.puts("writing").should == nil end - }.should raise_error(IOError) + }.should.raise(IOError) end end @@ -438,15 +438,15 @@ describe "File.open" do File.open(@file, File::TRUNC) do |f| f.puts("writing") end - }.should raise_error(Errno::EINVAL) + }.should.raise(Errno::EINVAL) end - it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do + it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do -> { File.open(@file, File::RDONLY|File::TRUNC) do |f| f.puts("writing").should == nil end - }.should raise_error(Errno::EINVAL) + }.should.raise(Errno::EINVAL) end end @@ -455,7 +455,7 @@ describe "File.open" do it "raises an Errno::EACCES when opening non-permitted file" do @fh = File.open(@file, "w") @fh.chmod(000) - -> { fh1 = File.open(@file); fh1.close }.should raise_error(Errno::EACCES) + -> { fh1 = File.open(@file); fh1.close }.should.raise(Errno::EACCES) end end end @@ -464,19 +464,19 @@ describe "File.open" do it "raises an Errno::EACCES when opening read-only file" do @fh = File.open(@file, "w") @fh.chmod(0444) - -> { File.open(@file, "w") }.should raise_error(Errno::EACCES) + -> { File.open(@file, "w") }.should.raise(Errno::EACCES) end end it "opens a file for binary read" do @fh = File.open(@file, "rb") - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end it "opens a file for binary write" do @fh = File.open(@file, "wb") - @fh.should be_kind_of(File) + @fh.should.is_a?(File) File.should.exist?(@file) end @@ -485,7 +485,7 @@ describe "File.open" do File.size(@file).should > 0 File.open(@file, "w+") do |f| f.pos.should == 0 - f.eof?.should == true + f.should.eof? end File.size(@file).should == 0 end @@ -494,8 +494,16 @@ describe "File.open" do File.open(@file, "w") { |f| f.puts "testing" } File.size(@file).should > 0 File.open(@file, "rb+") do |f| + f.binmode?.should == true + f.external_encoding.should == Encoding::ASCII_8BIT f.pos.should == 0 - f.eof?.should == false + f.should_not.eof? + end + File.open(@file, "r+b") do |f| + f.binmode?.should == true + f.external_encoding.should == Encoding::ASCII_8BIT + f.pos.should == 0 + f.should_not.eof? end end @@ -504,7 +512,7 @@ describe "File.open" do File.size(@file).should > 0 File.open(@file, "wb+") do |f| f.pos.should == 0 - f.eof?.should == true + f.should.eof? end File.size(@file).should == 0 end @@ -535,21 +543,21 @@ describe "File.open" do end it "raises a TypeError if passed a filename that is not a String or Integer type" do - -> { File.open(true) }.should raise_error(TypeError) - -> { File.open(false) }.should raise_error(TypeError) - -> { File.open(nil) }.should raise_error(TypeError) + -> { File.open(true) }.should.raise(TypeError) + -> { File.open(false) }.should.raise(TypeError) + -> { File.open(nil) }.should.raise(TypeError) end it "raises a SystemCallError if passed an invalid Integer type" do - -> { File.open(-1) }.should raise_error(SystemCallError) + -> { File.open(-1) }.should.raise(SystemCallError) end it "raises an ArgumentError if passed the wrong number of arguments" do - -> { File.open(@file, File::CREAT, 0755, 'test') }.should raise_error(ArgumentError) + -> { File.open(@file, File::CREAT, 0755, 'test') }.should.raise(ArgumentError) end it "raises an ArgumentError if passed an invalid string for mode" do - -> { File.open(@file, 'fake') }.should raise_error(ArgumentError) + -> { File.open(@file, 'fake') }.should.raise(ArgumentError) end it "defaults external_encoding to BINARY for binary modes" do @@ -557,9 +565,18 @@ describe "File.open" do File.open(@file, 'wb+') {|f| f.external_encoding.should == Encoding::BINARY} end + it "accepts options as a keyword argument" do + @fh = File.open(@file, 'w', 0755, flags: File::CREAT) + @fh.should.instance_of?(File) + + -> { + File.open(@file, 'w', 0755, {flags: File::CREAT}) + }.should.raise(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") + end + it "uses the second argument as an options Hash" do @fh = File.open(@file, mode: "r") - @fh.should be_an_instance_of(File) + @fh.should.instance_of?(File) end it "calls #to_hash to convert the second argument to a Hash" do @@ -572,17 +589,17 @@ describe "File.open" do it "accepts extra flags as a keyword argument and combine with a string mode" do -> { File.open(@file, "w", flags: File::EXCL) { } - }.should raise_error(Errno::EEXIST) + }.should.raise(Errno::EEXIST) -> { File.open(@file, mode: "w", flags: File::EXCL) { } - }.should raise_error(Errno::EEXIST) + }.should.raise(Errno::EEXIST) end it "accepts extra flags as a keyword argument and combine with an integer mode" do -> { File.open(@file, File::WRONLY | File::CREAT, flags: File::EXCL) { } - }.should raise_error(Errno::EEXIST) + }.should.raise(Errno::EEXIST) end platform_is_not :windows do @@ -623,39 +640,35 @@ describe "File.open" do end end - ruby_version_is "2.5" do - 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") - end + it "raises ArgumentError if mixing :newline and binary mode" do + -> { + File.open(@file, "rb", newline: :universal) {} + }.should.raise(ArgumentError, "newline decorator with binary mode") end - ruby_version_is "2.6" do - context "'x' flag" do - before :each do - @xfile = tmp("x-flag") - rm_r @xfile - end + context "'x' flag" do + before :each do + @xfile = tmp("x-flag") + rm_r @xfile + end - after :each do - 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 "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 - -> { File.open(@xfile, "wx") }.should raise_error(Errno::EEXIST) - end + it "throws a Errno::EEXIST error if the file exists" do + touch @xfile + -> { File.open(@xfile, "wx") }.should.raise(Errno::EEXIST) + end - it "can't be used with 'r' and 'a' flags" do - -> { File.open(@xfile, "rx") }.should raise_error(ArgumentError, 'invalid access mode rx') - -> { File.open(@xfile, "ax") }.should raise_error(ArgumentError, 'invalid access mode ax') - end + it "can't be used with 'r' and 'a' flags" do + -> { File.open(@xfile, "rx") }.should.raise(ArgumentError, 'invalid access mode rx') + -> { File.open(@xfile, "ax") }.should.raise(ArgumentError, 'invalid access mode ax') end end end @@ -675,8 +688,8 @@ describe "File.open when passed a file descriptor" do it "opens a file" do @file = File.open(@fd, "w") - @file.should be_an_instance_of(File) - @file.fileno.should equal(@fd) + @file.should.instance_of?(File) + @file.fileno.should.equal?(@fd) @file.write @content @file.flush File.read(@name).should == @content @@ -684,8 +697,8 @@ describe "File.open when passed a file descriptor" do 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.should.instance_of?(File) + f.fileno.should.equal?(@fd) f.write @content f end diff --git a/spec/ruby/core/file/path_spec.rb b/spec/ruby/core/file/path_spec.rb index dfa0c4ec02..ce78dbeede 100644 --- a/spec/ruby/core/file/path_spec.rb +++ b/spec/ruby/core/file/path_spec.rb @@ -37,4 +37,45 @@ describe "File.path" do path.should_receive(:to_path).and_return("abc") File.path(path).should == "abc" end + + it "raises TypeError when #to_path result is not a string" do + path = mock("path") + path.should_receive(:to_path).and_return(nil) + -> { File.path(path) }.should.raise TypeError + + path = mock("path") + path.should_receive(:to_path).and_return(42) + -> { File.path(path) }.should.raise TypeError + end + + it "raises ArgumentError for string argument contains NUL character" do + -> { File.path("\0") }.should.raise ArgumentError + -> { File.path("a\0") }.should.raise ArgumentError + -> { File.path("a\0c") }.should.raise ArgumentError + end + + it "raises ArgumentError when #to_path result contains NUL character" do + path = mock("path") + path.should_receive(:to_path).and_return("\0") + -> { File.path(path) }.should.raise ArgumentError + + path = mock("path") + path.should_receive(:to_path).and_return("a\0") + -> { File.path(path) }.should.raise ArgumentError + + path = mock("path") + path.should_receive(:to_path).and_return("a\0c") + -> { File.path(path) }.should.raise ArgumentError + end + + it "raises Encoding::CompatibilityError for ASCII-incompatible string argument" do + path = "abc".encode(Encoding::UTF_32BE) + -> { File.path(path) }.should.raise Encoding::CompatibilityError + end + + it "raises Encoding::CompatibilityError when #to_path result is ASCII-incompatible" do + path = mock("path") + path.should_receive(:to_path).and_return("abc".encode(Encoding::UTF_32BE)) + -> { File.path(path) }.should.raise Encoding::CompatibilityError + end end diff --git a/spec/ruby/core/file/readlink_spec.rb b/spec/ruby/core/file/readlink_spec.rb index eb3bfda30e..568692b9b6 100644 --- a/spec/ruby/core/file/readlink_spec.rb +++ b/spec/ruby/core/file/readlink_spec.rb @@ -26,12 +26,12 @@ describe "File.readlink" do it "raises an Errno::ENOENT if there is no such file" do # TODO: missing_file - -> { File.readlink("/this/surely/doesnt/exist") }.should raise_error(Errno::ENOENT) + -> { File.readlink("/this/surely/does/not/exist") }.should.raise(Errno::ENOENT) end it "raises an Errno::EINVAL if called with a normal file" do touch @file - -> { File.readlink(@file) }.should raise_error(Errno::EINVAL) + -> { File.readlink(@file) }.should.raise(Errno::EINVAL) end end @@ -49,7 +49,7 @@ describe "File.readlink" do it "returns the name of the file referenced by the given link" do touch @file result = File.readlink(@link) - result.encoding.should equal Encoding.find('filesystem') + result.encoding.should.equal? Encoding.find('filesystem') result.should == @file.dup.force_encoding(Encoding.find('filesystem')) end end diff --git a/spec/ruby/core/file/realdirpath_spec.rb b/spec/ruby/core/file/realdirpath_spec.rb index 74053afce3..ecf1e0c6d9 100644 --- a/spec/ruby/core/file/realdirpath_spec.rb +++ b/spec/ruby/core/file/realdirpath_spec.rb @@ -61,7 +61,7 @@ platform_is_not :windows do it "raises an Errno::ELOOP if the symlink points to itself" do File.unlink @link File.symlink(@link, @link) - -> { File.realdirpath(@link) }.should raise_error(Errno::ELOOP) + -> { File.realdirpath(@link) }.should.raise(Errno::ELOOP) end it "returns the real (absolute) pathname if the file is absent" do @@ -69,7 +69,7 @@ platform_is_not :windows do end it "raises Errno::ENOENT if the directory is absent" do - -> { File.realdirpath(@fake_file_in_fake_dir) }.should raise_error(Errno::ENOENT) + -> { File.realdirpath(@fake_file_in_fake_dir) }.should.raise(Errno::ENOENT) end it "returns the real (absolute) pathname if the symlink points to an absent file" do @@ -77,7 +77,7 @@ platform_is_not :windows do end it "raises Errno::ENOENT if the symlink points to an absent directory" do - -> { File.realdirpath(@fake_link_to_fake_dir) }.should raise_error(Errno::ENOENT) + -> { File.realdirpath(@fake_link_to_fake_dir) }.should.raise(Errno::ENOENT) end end end diff --git a/spec/ruby/core/file/realpath_spec.rb b/spec/ruby/core/file/realpath_spec.rb index 0c5d19287a..ccb981eff1 100644 --- a/spec/ruby/core/file/realpath_spec.rb +++ b/spec/ruby/core/file/realpath_spec.rb @@ -54,18 +54,28 @@ platform_is_not :windows do File.realpath(@relative_symlink).should == @file end + it "removes the file element when going one level up" do + File.realpath('../', @file).should == @real_dir + end + it "raises an Errno::ELOOP if the symlink points to itself" do File.unlink @link File.symlink(@link, @link) - -> { File.realpath(@link) }.should raise_error(Errno::ELOOP) + -> { File.realpath(@link) }.should.raise(Errno::ELOOP) end it "raises Errno::ENOENT if the file is absent" do - -> { File.realpath(@fake_file) }.should raise_error(Errno::ENOENT) + -> { File.realpath(@fake_file) }.should.raise(Errno::ENOENT) end it "raises Errno::ENOENT if the symlink points to an absent file" do - -> { File.realpath(@fake_link) }.should raise_error(Errno::ENOENT) + -> { File.realpath(@fake_link) }.should.raise(Errno::ENOENT) + end + + it "converts the argument with #to_path" do + path = mock("path") + path.should_receive(:to_path).and_return(__FILE__) + File.realpath(path).should == File.realpath(__FILE__ ) end end end diff --git a/spec/ruby/core/file/rename_spec.rb b/spec/ruby/core/file/rename_spec.rb index f2c18d4905..70ea669a68 100644 --- a/spec/ruby/core/file/rename_spec.rb +++ b/spec/ruby/core/file/rename_spec.rb @@ -23,15 +23,15 @@ describe "File.rename" do it "raises an Errno::ENOENT if the source does not exist" do rm_r @old - -> { File.rename(@old, @new) }.should raise_error(Errno::ENOENT) + -> { File.rename(@old, @new) }.should.raise(Errno::ENOENT) end it "raises an ArgumentError if not passed two arguments" do - -> { File.rename }.should raise_error(ArgumentError) - -> { File.rename(@file) }.should raise_error(ArgumentError) + -> { File.rename }.should.raise(ArgumentError) + -> { File.rename(@file) }.should.raise(ArgumentError) end it "raises a TypeError if not passed String types" do - -> { File.rename(1, 2) }.should raise_error(TypeError) + -> { File.rename(1, 2) }.should.raise(TypeError) end end diff --git a/spec/ruby/core/file/setuid_spec.rb b/spec/ruby/core/file/setuid_spec.rb index 281ef01ab9..9e5e86df61 100644 --- a/spec/ruby/core/file/setuid_spec.rb +++ b/spec/ruby/core/file/setuid_spec.rb @@ -26,10 +26,6 @@ describe "File.setuid?" do platform_is_not :windows do it "returns true when the gid bit is set" do - platform_is :solaris do - # Solaris requires execute bit before setting suid - system "chmod u+x #{@name}" - end system "chmod u+s #{@name}" File.setuid?(@name).should == true diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb index a8488fd30a..b9140d027d 100644 --- a/spec/ruby/core/file/shared/fnmatch.rb +++ b/spec/ruby/core/file/shared/fnmatch.rb @@ -75,6 +75,14 @@ describe :file_fnmatch, shared: true do File.send(@method, 'c*t', 'c/a/b/t').should == true end + it "does not match unterminated range of characters" do + File.send(@method, 'abc[de', 'abcd').should == false + end + + it "does not match unterminated range of characters as a literal" do + File.send(@method, 'abc[de', 'abc[de').should == false + end + it "matches ranges of characters using bracket expression (e.g. [a-z])" do File.send(@method, 'ca[a-z]', 'cat').should == true end @@ -94,6 +102,7 @@ describe :file_fnmatch, shared: true do it "matches ranges of characters using exclusive bracket expression (e.g. [^t] or [!t])" do File.send(@method, 'ca[^t]', 'cat').should == false + File.send(@method, 'ca[^t]', 'cas').should == true File.send(@method, 'ca[!t]', 'cat').should == false end @@ -117,6 +126,13 @@ describe :file_fnmatch, shared: true do end end + it "matches wildcard with characters when flags includes FNM_PATHNAME" do + File.send(@method, '*a', 'aa', File::FNM_PATHNAME).should == true + File.send(@method, 'a*', 'aa', File::FNM_PATHNAME).should == true + File.send(@method, 'a*', 'aaa', File::FNM_PATHNAME).should == true + File.send(@method, '*a', 'aaa', File::FNM_PATHNAME).should == true + end + it "does not match '/' characters with ? or * when flags includes FNM_PATHNAME" do File.send(@method, '?', '/', File::FNM_PATHNAME).should == false File.send(@method, '*', '/', File::FNM_PATHNAME).should == false @@ -151,15 +167,25 @@ describe :file_fnmatch, shared: true do end it "does not match leading periods in filenames with wildcards by default" do - File.send(@method, '*', '.profile').should == false - File.send(@method, '*', 'home/.profile').should == true - File.send(@method, '*/*', 'home/.profile').should == true - File.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME).should == false + File.should_not.send(@method, '*', '.profile') + File.should.send(@method, '*', 'home/.profile') + File.should.send(@method, '*/*', 'home/.profile') + File.should_not.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME) end - it "matches patterns with leading periods to dotfiles by default" do + it "matches patterns with leading periods to dotfiles" do File.send(@method, '.*', '.profile').should == true + File.send(@method, '.*', '.profile', File::FNM_PATHNAME).should == true File.send(@method, ".*file", "nondotfile").should == false + File.send(@method, ".*file", "nondotfile", File::FNM_PATHNAME).should == false + end + + it "does not match directories with leading periods by default with FNM_PATHNAME" do + File.send(@method, '.*', '.directory/nondotfile', File::FNM_PATHNAME).should == false + File.send(@method, '.*', '.directory/.profile', File::FNM_PATHNAME).should == false + File.send(@method, '.*', 'foo/.directory/nondotfile', File::FNM_PATHNAME).should == false + File.send(@method, '.*', 'foo/.directory/.profile', File::FNM_PATHNAME).should == false + File.send(@method, '**/.dotfile', '.dotsubdir/.dotfile', File::FNM_PATHNAME).should == false end it "matches leading periods in filenames when flags includes FNM_DOTMATCH" do @@ -196,21 +222,48 @@ describe :file_fnmatch, shared: true do it "returns false if '/' in pattern do not match '/' in path when flags includes FNM_PATHNAME" do pattern = '*/*' - File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME).should be_false + File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME).should == false pattern = '**/foo' - File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME).should be_false + File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME).should == false end it "returns true if '/' in pattern match '/' in path when flags includes FNM_PATHNAME" do pattern = '*/*' - File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true + File.send(@method, pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true pattern = '**/foo' - File.send(@method, pattern, 'a/b/c/foo', File::FNM_PATHNAME).should be_true - File.send(@method, pattern, '/a/b/c/foo', File::FNM_PATHNAME).should be_true - File.send(@method, pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME).should be_true - File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true + File.send(@method, pattern, 'a/b/c/foo', File::FNM_PATHNAME).should == true + File.send(@method, pattern, '/a/b/c/foo', File::FNM_PATHNAME).should == true + File.send(@method, pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME).should == true + File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true + end + + it "has special handling for ./ when using * and FNM_PATHNAME" do + File.send(@method, './*', '.', File::FNM_PATHNAME).should == false + File.send(@method, './*', './', File::FNM_PATHNAME).should == true + File.send(@method, './*/', './', File::FNM_PATHNAME).should == false + File.send(@method, './**', './', File::FNM_PATHNAME).should == true + File.send(@method, './**/', './', File::FNM_PATHNAME).should == true + File.send(@method, './*', '.', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false + File.send(@method, './*', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true + File.send(@method, './*/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false + File.send(@method, './**', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true + File.send(@method, './**/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true + end + + it "matches **/* with FNM_PATHNAME to recurse directories" do + File.send(@method, 'nested/**/*', 'nested/subdir', File::FNM_PATHNAME).should == true + File.send(@method, 'nested/**/*', 'nested/subdir/file', File::FNM_PATHNAME).should == true + File.send(@method, 'nested/**/*', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true + File.send(@method, 'nested/**/*', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true + end + + it "matches ** with FNM_PATHNAME only in current directory" do + File.send(@method, 'nested/**', 'nested/subdir', File::FNM_PATHNAME).should == true + File.send(@method, 'nested/**', 'nested/subdir/file', File::FNM_PATHNAME).should == false + File.send(@method, 'nested/**', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == true + File.send(@method, 'nested/**', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should == false end it "accepts an object that has a #to_path method" do @@ -218,21 +271,21 @@ describe :file_fnmatch, shared: true do end it "raises a TypeError if the first and second arguments are not string-like" do - -> { File.send(@method, nil, nil, 0, 0) }.should raise_error(ArgumentError) - -> { File.send(@method, 1, 'some/thing') }.should raise_error(TypeError) - -> { File.send(@method, 'some/thing', 1) }.should raise_error(TypeError) - -> { File.send(@method, 1, 1) }.should raise_error(TypeError) + -> { File.send(@method, nil, nil, 0, 0) }.should.raise(ArgumentError) + -> { File.send(@method, 1, 'some/thing') }.should.raise(TypeError) + -> { File.send(@method, 'some/thing', 1) }.should.raise(TypeError) + -> { File.send(@method, 1, 1) }.should.raise(TypeError) end it "raises a TypeError if the third argument is not an Integer" do - -> { File.send(@method, "*/place", "path/to/file", "flags") }.should raise_error(TypeError) - -> { File.send(@method, "*/place", "path/to/file", nil) }.should raise_error(TypeError) + -> { File.send(@method, "*/place", "path/to/file", "flags") }.should.raise(TypeError) + -> { File.send(@method, "*/place", "path/to/file", nil) }.should.raise(TypeError) end it "does not raise a TypeError if the third argument can be coerced to an Integer" do flags = mock("flags") flags.should_receive(:to_int).and_return(10) - -> { File.send(@method, "*/place", "path/to/file", flags) }.should_not raise_error + -> { File.send(@method, "*/place", "path/to/file", flags) }.should_not.raise end it "matches multibyte characters" do diff --git a/spec/ruby/core/file/shared/open.rb b/spec/ruby/core/file/shared/open.rb index 677a82a351..67149235ca 100644 --- a/spec/ruby/core/file/shared/open.rb +++ b/spec/ruby/core/file/shared/open.rb @@ -4,7 +4,7 @@ describe :open_directory, shared: true do it "opens directories" do file = File.send(@method, tmp("")) begin - file.should be_kind_of(File) + file.should.is_a?(File) ensure file.close end diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb index cfd119f799..6c6f7d4234 100644 --- a/spec/ruby/core/file/shared/path.rb +++ b/spec/ruby/core/file/shared/path.rb @@ -1,7 +1,7 @@ describe :file_path, shared: true do before :each do - @name = "file_to_path" - @path = tmp(@name) + @path = tmp("file_to_path") + @name = File.basename(@path) touch @path end @@ -12,7 +12,24 @@ describe :file_path, shared: true do it "returns a String" do @file = File.new @path - @file.send(@method).should be_an_instance_of(String) + @file.send(@method).should.instance_of?(String) + end + + it "returns a different String on every call" do + @file = File.new @path + path1 = @file.send(@method) + path2 = @file.send(@method) + path1.should == path2 + path1.should_not.equal?(path2) + end + + it "returns a mutable String" do + @file = File.new @path.dup.freeze + path = @file.send(@method) + path.should == @path + path.should_not.frozen? + path << "test" + @file.send(@method).should == @path end it "calls to_str on argument and returns exact value" do @@ -50,27 +67,15 @@ describe :file_path, shared: true do @file.send(@method).encoding.should == Encoding.find("euc-jp") end - ruby_version_is "2.5" do - platform_is :linux do - guard -> { defined?(File::TMPFILE) } do - before :each do - @dir = tmp("tmpfilespec") - mkdir_p @dir - end - - after :each do - rm_r @dir - end + platform_is :linux do + guard -> { defined?(File::TMPFILE) } do + before :each do + @dir = tmp("tmpfilespec") + mkdir_p @dir + end - it "raises IOError if file was opened with File::TMPFILE" do - begin - File.open(@dir, File::RDWR | File::TMPFILE) do |f| - -> { f.send(@method) }.should raise_error(IOError) - end - rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR - skip "no support from the filesystem" - end - end + after :each do + rm_r @dir end end end diff --git a/spec/ruby/core/file/shared/read.rb b/spec/ruby/core/file/shared/read.rb index a2d479966d..f60800bb2f 100644 --- a/spec/ruby/core/file/shared/read.rb +++ b/spec/ruby/core/file/shared/read.rb @@ -1,15 +1,15 @@ require_relative '../../dir/fixtures/common' describe :file_read_directory, shared: true do - platform_is :darwin, :linux, :openbsd, :windows do + platform_is :darwin, :linux, :freebsd, :openbsd, :windows do it "raises an Errno::EISDIR when passed a path that is a directory" do - -> { @object.send(@method, ".") }.should raise_error(Errno::EISDIR) + -> { @object.send(@method, ".") }.should.raise(Errno::EISDIR) end end - platform_is :freebsd, :netbsd do + platform_is :netbsd do it "does not raises any exception when passed a path that is a directory" do - -> { @object.send(@method, ".") }.should_not raise_error + -> { @object.send(@method, ".") }.should_not.raise end end end diff --git a/spec/ruby/core/file/shared/stat.rb b/spec/ruby/core/file/shared/stat.rb index fdaf97ea61..879a7f11ff 100644 --- a/spec/ruby/core/file/shared/stat.rb +++ b/spec/ruby/core/file/shared/stat.rb @@ -10,13 +10,13 @@ describe :file_stat, shared: true do it "returns a File::Stat object if the given file exists" do st = File.send(@method, @file) - st.should be_an_instance_of(File::Stat) + st.should.instance_of?(File::Stat) end it "returns a File::Stat object when called on an instance of File" do File.open(@file) do |f| st = f.send(@method) - st.should be_an_instance_of(File::Stat) + st.should.instance_of?(File::Stat) end end @@ -27,6 +27,6 @@ describe :file_stat, shared: true do it "raises an Errno::ENOENT if the file does not exist" do -> { File.send(@method, "fake_file") - }.should raise_error(Errno::ENOENT) + }.should.raise(Errno::ENOENT) end end diff --git a/spec/ruby/core/file/shared/unlink.rb b/spec/ruby/core/file/shared/unlink.rb index e339e93271..0032907ba2 100644 --- a/spec/ruby/core/file/shared/unlink.rb +++ b/spec/ruby/core/file/shared/unlink.rb @@ -31,11 +31,11 @@ describe :file_unlink, shared: true do end it "raises a TypeError if not passed a String type" do - -> { File.send(@method, 1) }.should raise_error(TypeError) + -> { File.send(@method, 1) }.should.raise(TypeError) end it "raises an Errno::ENOENT when the given file doesn't exist" do - -> { File.send(@method, 'bogus') }.should raise_error(Errno::ENOENT) + -> { File.send(@method, 'bogus') }.should.raise(Errno::ENOENT) end it "coerces a given parameter into a string if possible" do diff --git a/spec/ruby/core/file/shared/update_time.rb b/spec/ruby/core/file/shared/update_time.rb new file mode 100644 index 0000000000..3fe7266a00 --- /dev/null +++ b/spec/ruby/core/file/shared/update_time.rb @@ -0,0 +1,105 @@ +describe :update_time, shared: true do + before :all do + @time_is_float = platform_is :windows + end + + before :each do + @atime = Time.now + @mtime = Time.now + @file1 = tmp("specs_file_utime1") + @file2 = tmp("specs_file_utime2") + touch @file1 + touch @file2 + end + + after :each do + rm_r @file1, @file2 + end + + it "sets the access and modification time of each file" do + File.send(@method, @atime, @mtime, @file1, @file2) + + if @time_is_float + File.atime(@file1).should be_close(@atime, 0.0001) + File.mtime(@file1).should be_close(@mtime, 0.0001) + File.atime(@file2).should be_close(@atime, 0.0001) + File.mtime(@file2).should be_close(@mtime, 0.0001) + else + File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE) + File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE) + File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE) + File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE) + end + end + + it "uses the current times if two nil values are passed" do + tn = Time.now + File.send(@method, nil, nil, @file1, @file2) + + if @time_is_float + File.atime(@file1).should be_close(tn, 0.050) + File.mtime(@file1).should be_close(tn, 0.050) + File.atime(@file2).should be_close(tn, 0.050) + File.mtime(@file2).should be_close(tn, 0.050) + else + File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE) + File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE) + File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE) + File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE) + end + end + + it "accepts an object that has a #to_path method" do + File.send(@method, @atime, @mtime, mock_to_path(@file1), mock_to_path(@file2)) + end + + it "accepts numeric atime and mtime arguments" do + if @time_is_float + File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2) + + File.atime(@file1).should be_close(@atime, 0.0001) + File.mtime(@file1).should be_close(@mtime, 0.0001) + File.atime(@file2).should be_close(@atime, 0.0001) + File.mtime(@file2).should be_close(@mtime, 0.0001) + else + File.send(@method, @atime.to_i, @mtime.to_i, @file1, @file2) + + File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE) + File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE) + File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE) + File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE) + end + end + + it "may set nanosecond precision" do + t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r) + File.send(@method, t, t, @file1) + + File.atime(@file1).nsec.should.between?(0, 123500000) + File.mtime(@file1).nsec.should.between?(0, 123500000) + end + + it "returns the number of filenames in the arguments" do + File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2).should == 2 + end + + platform_is :linux do + platform_is pointer_size: 64 do + it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do + # https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps + # "Therefore, timestamps should not overflow until May 2446." + # https://lwn.net/Articles/804382/ + # "On-disk timestamps hitting the y2038 limit..." + # The problem seems to be being improved, but currently it actually fails on XFS on RHEL8 + # https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz + # Amazon Linux 2023 returns 2486-07-02 in this example + # http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz + time = Time.at(1<<44) + File.send(@method, time, time, @file1) + + [559444, 2486, 2446, 2038].should.include? File.atime(@file1).year + [559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year + end + end + end +end diff --git a/spec/ruby/core/file/size_spec.rb b/spec/ruby/core/file/size_spec.rb index a2bf408da1..784c18c26e 100644 --- a/spec/ruby/core/file/size_spec.rb +++ b/spec/ruby/core/file/size_spec.rb @@ -56,11 +56,11 @@ describe "File#size" do end it "is an instance method" do - @file.respond_to?(:size).should be_true + @file.respond_to?(:size).should == true end - it "returns the file's size as a Fixnum" do - @file.size.should be_an_instance_of(Fixnum) + it "returns the file's size as an Integer" do + @file.size.should.instance_of?(Integer) end it "returns the file's size in bytes" do @@ -81,7 +81,7 @@ describe "File#size" do it "raises an IOError on a closed file" do @file.close - -> { @file.size }.should raise_error(IOError) + -> { @file.size }.should.raise(IOError) end platform_is_not :windows do diff --git a/spec/ruby/core/file/socket_spec.rb b/spec/ruby/core/file/socket_spec.rb index 5d12e21f55..d3f4eb013a 100644 --- a/spec/ruby/core/file/socket_spec.rb +++ b/spec/ruby/core/file/socket_spec.rb @@ -1,42 +1,10 @@ require_relative '../../spec_helper' require_relative '../../shared/file/socket' -require 'socket' describe "File.socket?" do it_behaves_like :file_socket, :socket?, File -end -describe "File.socket?" do it "returns false if file does not exist" do File.socket?("I_am_a_bogus_file").should == false end - - it "returns false if the file is not a socket" do - filename = tmp("i_exist") - touch(filename) - - File.socket?(filename).should == false - - rm_r filename - end -end - -platform_is_not :windows do - describe "File.socket?" do - before :each do - # We need a really short name here. - # On Linux the path length is limited to 107, see unix(7). - @name = tmp("s") - @server = UNIXServer.new @name - end - - after :each do - @server.close - rm_r @name - end - - it "returns true if the file is a socket" do - File.socket?(@name).should == true - end - end end diff --git a/spec/ruby/core/file/split_spec.rb b/spec/ruby/core/file/split_spec.rb index 7b958621b9..e989a6b86e 100644 --- a/spec/ruby/core/file/split_spec.rb +++ b/spec/ruby/core/file/split_spec.rb @@ -44,12 +44,12 @@ describe "File.split" do end it "raises an ArgumentError when not passed a single argument" do - -> { File.split }.should raise_error(ArgumentError) - -> { File.split('string', 'another string') }.should raise_error(ArgumentError) + -> { File.split }.should.raise(ArgumentError) + -> { File.split('string', 'another string') }.should.raise(ArgumentError) end it "raises a TypeError if the argument is not a String type" do - -> { File.split(1) }.should raise_error(TypeError) + -> { File.split(1) }.should.raise(TypeError) end it "coerces the argument with to_str if it is not a String type" do diff --git a/spec/ruby/core/file/stat/atime_spec.rb b/spec/ruby/core/file/stat/atime_spec.rb index 9f1111ced1..2fecaed300 100644 --- a/spec/ruby/core/file/stat/atime_spec.rb +++ b/spec/ruby/core/file/stat/atime_spec.rb @@ -12,7 +12,7 @@ describe "File::Stat#atime" do it "returns the atime of a File::Stat object" do st = File.stat(@file) - st.atime.should be_kind_of(Time) + st.atime.should.is_a?(Time) st.atime.should <= Time.now end end diff --git a/spec/ruby/core/file/stat/birthtime_spec.rb b/spec/ruby/core/file/stat/birthtime_spec.rb index a727bbe566..728f635397 100644 --- a/spec/ruby/core/file/stat/birthtime_spec.rb +++ b/spec/ruby/core/file/stat/birthtime_spec.rb @@ -1,27 +1,29 @@ require_relative '../../../spec_helper' -describe "File::Stat#birthtime" do - before :each do - @file = tmp('i_exist') - touch(@file) { |f| f.write "rubinius" } - end +platform_is(:windows, :darwin, :freebsd, :netbsd, + *ruby_version_is("4.0") { :linux }, + ) do + not_implemented_messages = [ + "birthtime() function is unimplemented", # unsupported OS/version + "birthtime is unimplemented", # unsupported filesystem + ] - after :each do - rm_r @file - end + describe "File::Stat#birthtime" do + before :each do + @file = tmp('i_exist') + touch(@file) { |f| f.write "rubinius" } + end - platform_is :windows, :darwin, :freebsd, :netbsd do - it "returns the birthtime of a File::Stat object" do - st = File.stat(@file) - st.birthtime.should be_kind_of(Time) - st.birthtime.should <= Time.now + after :each do + rm_r @file end - end - platform_is :linux, :openbsd do - it "raises an NotImplementedError" do + it "returns the birthtime of a File::Stat object" do st = File.stat(@file) - -> { st.birthtime }.should raise_error(NotImplementedError) + st.birthtime.should.is_a?(Time) + st.birthtime.should <= Time.now + rescue NotImplementedError => e + e.message.should.start_with?(*not_implemented_messages) end end end diff --git a/spec/ruby/core/file/stat/blocks_spec.rb b/spec/ruby/core/file/stat/blocks_spec.rb index f3f903d0f7..5e0efc8bc2 100644 --- a/spec/ruby/core/file/stat/blocks_spec.rb +++ b/spec/ruby/core/file/stat/blocks_spec.rb @@ -21,7 +21,7 @@ describe "File::Stat#blocks" do platform_is :windows do it "returns nil" do st = File.stat(@file) - st.blocks.should be_nil + st.blocks.should == nil end end end diff --git a/spec/ruby/core/file/stat/ctime_spec.rb b/spec/ruby/core/file/stat/ctime_spec.rb index fd50487a0a..dbf43a7453 100644 --- a/spec/ruby/core/file/stat/ctime_spec.rb +++ b/spec/ruby/core/file/stat/ctime_spec.rb @@ -12,7 +12,7 @@ describe "File::Stat#ctime" do it "returns the ctime of a File::Stat object" do st = File.stat(@file) - st.ctime.should be_kind_of(Time) + st.ctime.should.is_a?(Time) st.ctime.should <= Time.now end end diff --git a/spec/ruby/core/file/stat/dev_major_spec.rb b/spec/ruby/core/file/stat/dev_major_spec.rb index 4966d609e2..a199eaaa11 100644 --- a/spec/ruby/core/file/stat/dev_major_spec.rb +++ b/spec/ruby/core/file/stat/dev_major_spec.rb @@ -11,13 +11,13 @@ describe "File::Stat#dev_major" do platform_is_not :windows do it "returns the major part of File::Stat#dev" do - File.stat(@name).dev_major.should be_kind_of(Integer) + File.stat(@name).dev_major.should.is_a?(Integer) end end platform_is :windows do it "returns nil" do - File.stat(@name).dev_major.should be_nil + File.stat(@name).dev_major.should == nil end end end diff --git a/spec/ruby/core/file/stat/dev_minor_spec.rb b/spec/ruby/core/file/stat/dev_minor_spec.rb index ea79c12b99..8ce94778ca 100644 --- a/spec/ruby/core/file/stat/dev_minor_spec.rb +++ b/spec/ruby/core/file/stat/dev_minor_spec.rb @@ -11,13 +11,13 @@ describe "File::Stat#dev_minor" do platform_is_not :windows do it "returns the minor part of File::Stat#dev" do - File.stat(@name).dev_minor.should be_kind_of(Integer) + File.stat(@name).dev_minor.should.is_a?(Integer) end end platform_is :windows do it "returns nil" do - File.stat(@name).dev_minor.should be_nil + File.stat(@name).dev_minor.should == nil end end end diff --git a/spec/ruby/core/file/stat/dev_spec.rb b/spec/ruby/core/file/stat/dev_spec.rb index e953fcaa58..cd5e3d175e 100644 --- a/spec/ruby/core/file/stat/dev_spec.rb +++ b/spec/ruby/core/file/stat/dev_spec.rb @@ -10,6 +10,6 @@ describe "File::Stat#dev" do end it "returns the number of the device on which the file exists" do - File.stat(@name).dev.should be_kind_of(Integer) + File.stat(@name).dev.should.is_a?(Integer) end end diff --git a/spec/ruby/core/file/stat/ftype_spec.rb b/spec/ruby/core/file/stat/ftype_spec.rb index eb892eae5f..df2e3ada1e 100644 --- a/spec/ruby/core/file/stat/ftype_spec.rb +++ b/spec/ruby/core/file/stat/ftype_spec.rb @@ -8,7 +8,7 @@ describe "File::Stat#ftype" do it "returns a String" do FileSpecs.normal_file do |file| - File.lstat(file).ftype.should be_kind_of(String) + File.lstat(file).ftype.should.is_a?(String) end end diff --git a/spec/ruby/core/file/stat/ino_spec.rb b/spec/ruby/core/file/stat/ino_spec.rb index 42370aecb7..c09b6448c7 100644 --- a/spec/ruby/core/file/stat/ino_spec.rb +++ b/spec/ruby/core/file/stat/ino_spec.rb @@ -13,7 +13,7 @@ describe "File::Stat#ino" do platform_is_not :windows do it "returns the ino of a File::Stat object" do st = File.stat(@file) - st.ino.should be_kind_of(Integer) + st.ino.should.is_a?(Integer) st.ino.should > 0 end end @@ -21,7 +21,7 @@ describe "File::Stat#ino" do platform_is :windows do it "returns BY_HANDLE_FILE_INFORMATION.nFileIndexHigh/Low of a File::Stat object" do st = File.stat(@file) - st.ino.should be_kind_of(Integer) + st.ino.should.is_a?(Integer) st.ino.should > 0 end end diff --git a/spec/ruby/core/file/stat/mtime_spec.rb b/spec/ruby/core/file/stat/mtime_spec.rb index 08a2b83463..7844491212 100644 --- a/spec/ruby/core/file/stat/mtime_spec.rb +++ b/spec/ruby/core/file/stat/mtime_spec.rb @@ -12,7 +12,7 @@ describe "File::Stat#mtime" do it "returns the mtime of a File::Stat object" do st = File.stat(@file) - st.mtime.should be_kind_of(Time) + st.mtime.should.is_a?(Time) st.mtime.should <= Time.now end end diff --git a/spec/ruby/core/file/stat/new_spec.rb b/spec/ruby/core/file/stat/new_spec.rb index c0d9432ac8..b8c3600028 100644 --- a/spec/ruby/core/file/stat/new_spec.rb +++ b/spec/ruby/core/file/stat/new_spec.rb @@ -15,12 +15,12 @@ describe "File::Stat#initialize" do it "raises an exception if the file doesn't exist" do -> { File::Stat.new(tmp("i_am_a_dummy_file_that_doesnt_exist")) - }.should raise_error(Errno::ENOENT) + }.should.raise(Errno::ENOENT) end it "creates a File::Stat object for the given file" do st = File::Stat.new(@file) - st.should be_kind_of(File::Stat) + st.should.is_a?(File::Stat) st.ftype.should == 'file' end diff --git a/spec/ruby/core/file/stat/nlink_spec.rb b/spec/ruby/core/file/stat/nlink_spec.rb index 2dd0bff124..7143923cfc 100644 --- a/spec/ruby/core/file/stat/nlink_spec.rb +++ b/spec/ruby/core/file/stat/nlink_spec.rb @@ -11,7 +11,7 @@ describe "File::Stat#nlink" do rm_r @link, @file end - platform_is_not :windows do + platform_is_not :windows, :android do it "returns the number of links to a file" do File::Stat.new(@file).nlink.should == 1 File.link(@file, @link) diff --git a/spec/ruby/core/file/stat/owned_spec.rb b/spec/ruby/core/file/stat/owned_spec.rb index 6f0c250f88..a23ad850c5 100644 --- a/spec/ruby/core/file/stat/owned_spec.rb +++ b/spec/ruby/core/file/stat/owned_spec.rb @@ -18,15 +18,15 @@ describe "File::Stat#owned?" do it "returns true if the file is owned by the user" do st = File.stat(@file) - st.owned?.should == true + st.should.owned? end - platform_is_not :windows do + platform_is_not :windows, :android do as_user do it "returns false if the file is not owned by the user" do system_file = '/etc/passwd' st = File.stat(system_file) - st.owned?.should == false + st.should_not.owned? end end end diff --git a/spec/ruby/core/file/stat/pipe_spec.rb b/spec/ruby/core/file/stat/pipe_spec.rb index 7abb6c742a..692dfbf42a 100644 --- a/spec/ruby/core/file/stat/pipe_spec.rb +++ b/spec/ruby/core/file/stat/pipe_spec.rb @@ -12,7 +12,7 @@ describe "File::Stat#pipe?" do touch(filename) st = File.stat(filename) - st.pipe?.should == false + st.should_not.pipe? rm_r filename end @@ -23,7 +23,7 @@ describe "File::Stat#pipe?" do File.mkfifo(filename) st = File.stat(filename) - st.pipe?.should == true + st.should.pipe? rm_r filename end diff --git a/spec/ruby/core/file/stat/rdev_major_spec.rb b/spec/ruby/core/file/stat/rdev_major_spec.rb index f8a8d1b107..e1b44fc2d0 100644 --- a/spec/ruby/core/file/stat/rdev_major_spec.rb +++ b/spec/ruby/core/file/stat/rdev_major_spec.rb @@ -2,30 +2,23 @@ require_relative '../../../spec_helper' describe "File::Stat#rdev_major" do before :each do - platform_is :solaris do - @name = "/dev/zfs" - end - platform_is_not :solaris do - @name = tmp("file.txt") - touch(@name) - end + @name = tmp("file.txt") + touch(@name) end after :each do - platform_is_not :solaris do - rm_r @name - end + rm_r @name end platform_is_not :windows do it "returns the major part of File::Stat#rdev" do - File.stat(@name).rdev_major.should be_kind_of(Integer) + File.stat(@name).rdev_major.should.is_a?(Integer) end end platform_is :windows do it "returns nil" do - File.stat(@name).rdev_major.should be_nil + File.stat(@name).rdev_major.should == nil end end end diff --git a/spec/ruby/core/file/stat/rdev_minor_spec.rb b/spec/ruby/core/file/stat/rdev_minor_spec.rb index dc30c1f56c..8af3b9f587 100644 --- a/spec/ruby/core/file/stat/rdev_minor_spec.rb +++ b/spec/ruby/core/file/stat/rdev_minor_spec.rb @@ -2,30 +2,23 @@ require_relative '../../../spec_helper' describe "File::Stat#rdev_minor" do before :each do - platform_is :solaris do - @name = "/dev/zfs" - end - platform_is_not :solaris do - @name = tmp("file.txt") - touch(@name) - end + @name = tmp("file.txt") + touch(@name) end after :each do - platform_is_not :solaris do - rm_r @name - end + rm_r @name end platform_is_not :windows do it "returns the minor part of File::Stat#rdev" do - File.stat(@name).rdev_minor.should be_kind_of(Integer) + File.stat(@name).rdev_minor.should.is_a?(Integer) end end platform_is :windows do it "returns nil" do - File.stat(@name).rdev_minor.should be_nil + File.stat(@name).rdev_minor.should == nil end end end diff --git a/spec/ruby/core/file/stat/rdev_spec.rb b/spec/ruby/core/file/stat/rdev_spec.rb index 9e1aee692d..7e4252fcc6 100644 --- a/spec/ruby/core/file/stat/rdev_spec.rb +++ b/spec/ruby/core/file/stat/rdev_spec.rb @@ -10,6 +10,6 @@ describe "File::Stat#rdev" do end it "returns the number of the device this file represents which the file exists" do - File.stat(@name).rdev.should be_kind_of(Integer) + File.stat(@name).rdev.should.is_a?(Integer) end end diff --git a/spec/ruby/core/file/stat_spec.rb b/spec/ruby/core/file/stat_spec.rb index 31f9dc58af..d5238b6331 100644 --- a/spec/ruby/core/file/stat_spec.rb +++ b/spec/ruby/core/file/stat_spec.rb @@ -23,14 +23,14 @@ platform_is_not :windows do st = f.stat - st.file?.should == true - st.zero?.should == false + st.should.file? + st.should_not.zero? st.size.should == 8 st.size?.should == 8 st.blksize.should >= 0 - st.atime.should be_kind_of(Time) - st.ctime.should be_kind_of(Time) - st.mtime.should be_kind_of(Time) + st.atime.should.is_a?(Time) + st.ctime.should.is_a?(Time) + st.mtime.should.is_a?(Time) end end @@ -38,8 +38,18 @@ platform_is_not :windows do File.symlink(@file, @link) st = File.stat(@link) - st.file?.should == true - st.symlink?.should == false + st.should.file? + st.should_not.symlink? + end + + it "returns an error when given missing non-ASCII path" do + missing_path = "/missingfilepath\xE3E4".b + -> { + File.stat(missing_path) + }.should.raise(SystemCallError) { |e| + [Errno::ENOENT, Errno::EILSEQ].should.include?(e.class) + e.message.should.include?(missing_path) + } end end end diff --git a/spec/ruby/core/file/symlink_spec.rb b/spec/ruby/core/file/symlink_spec.rb index 0e8b0a5a20..4ceeb28c84 100644 --- a/spec/ruby/core/file/symlink_spec.rb +++ b/spec/ruby/core/file/symlink_spec.rb @@ -32,18 +32,18 @@ describe "File.symlink" do it "raises an Errno::EEXIST if the target already exists" do File.symlink(@file, @link) - -> { File.symlink(@file, @link) }.should raise_error(Errno::EEXIST) + -> { File.symlink(@file, @link) }.should.raise(Errno::EEXIST) end it "raises an ArgumentError if not called with two arguments" do - -> { File.symlink }.should raise_error(ArgumentError) - -> { File.symlink(@file) }.should raise_error(ArgumentError) + -> { File.symlink }.should.raise(ArgumentError) + -> { File.symlink(@file) }.should.raise(ArgumentError) end it "raises a TypeError if not called with String types" do - -> { File.symlink(@file, nil) }.should raise_error(TypeError) - -> { File.symlink(@file, 1) }.should raise_error(TypeError) - -> { File.symlink(1, 1) }.should raise_error(TypeError) + -> { File.symlink(@file, nil) }.should.raise(TypeError) + -> { File.symlink(@file, 1) }.should.raise(TypeError) + -> { File.symlink(1, 1) }.should.raise(TypeError) end end end diff --git a/spec/ruby/core/file/truncate_spec.rb b/spec/ruby/core/file/truncate_spec.rb index 43b86b7382..5f37f34155 100644 --- a/spec/ruby/core/file/truncate_spec.rb +++ b/spec/ruby/core/file/truncate_spec.rb @@ -18,7 +18,7 @@ describe "File.truncate" do File.open(@name, "r") do |f| f.read(99).should == "12345" - f.eof?.should == true + f.should.eof? end end @@ -54,29 +54,29 @@ describe "File.truncate" do rm_r not_existing_file begin - -> { File.truncate(not_existing_file, 5) }.should raise_error(Errno::ENOENT) + -> { File.truncate(not_existing_file, 5) }.should.raise(Errno::ENOENT) ensure rm_r not_existing_file end end it "raises an ArgumentError if not passed two arguments" do - -> { File.truncate }.should raise_error(ArgumentError) - -> { File.truncate(@name) }.should raise_error(ArgumentError) + -> { File.truncate }.should.raise(ArgumentError) + -> { File.truncate(@name) }.should.raise(ArgumentError) end platform_is_not :netbsd, :openbsd do it "raises an Errno::EINVAL if the length argument is not valid" do - -> { File.truncate(@name, -1) }.should raise_error(Errno::EINVAL) # May fail + -> { File.truncate(@name, -1) }.should.raise(Errno::EINVAL) # May fail end end it "raises a TypeError if not passed a String type for the first argument" do - -> { File.truncate(1, 1) }.should raise_error(TypeError) + -> { File.truncate(1, 1) }.should.raise(TypeError) end it "raises a TypeError if not passed an Integer type for the second argument" do - -> { File.truncate(@name, nil) }.should raise_error(TypeError) + -> { File.truncate(@name, nil) }.should.raise(TypeError) end it "accepts an object that has a #to_path method" do @@ -120,7 +120,7 @@ describe "File#truncate" do File.size(@name).should == 5 File.open(@name, "r") do |f| f.read(99).should == "12345" - f.eof?.should == true + f.should.eof? end end @@ -149,29 +149,29 @@ describe "File#truncate" do end it "raises an ArgumentError if not passed one argument" do - -> { @file.truncate }.should raise_error(ArgumentError) - -> { @file.truncate(1) }.should_not raise_error(ArgumentError) + -> { @file.truncate }.should.raise(ArgumentError) + -> { @file.truncate(1) }.should_not.raise(ArgumentError) end platform_is_not :netbsd do it "raises an Errno::EINVAL if the length argument is not valid" do - -> { @file.truncate(-1) }.should raise_error(Errno::EINVAL) # May fail + -> { @file.truncate(-1) }.should.raise(Errno::EINVAL) # May fail end end it "raises an IOError if file is closed" do @file.close - @file.closed?.should == true - -> { @file.truncate(42) }.should raise_error(IOError) + @file.should.closed? + -> { @file.truncate(42) }.should.raise(IOError) end it "raises an IOError if file is not opened for writing" do File.open(@name, 'r') do |file| - -> { file.truncate(42) }.should raise_error(IOError) + -> { file.truncate(42) }.should.raise(IOError) end end it "raises a TypeError if not passed an Integer type for the for the argument" do - -> { @file.truncate(nil) }.should raise_error(TypeError) + -> { @file.truncate(nil) }.should.raise(TypeError) end end diff --git a/spec/ruby/core/file/umask_spec.rb b/spec/ruby/core/file/umask_spec.rb index 2640e3c316..fea8cf7633 100644 --- a/spec/ruby/core/file/umask_spec.rb +++ b/spec/ruby/core/file/umask_spec.rb @@ -12,8 +12,8 @@ describe "File.umask" do File.umask(@orig_umask) end - it "returns a Fixnum" do - File.umask.should be_kind_of(Fixnum) + it "returns an Integer" do + File.umask.should.is_a?(Integer) end platform_is_not :windows do @@ -47,11 +47,11 @@ describe "File.umask" do end it "raises RangeError with too large values" do - -> { File.umask(2**64) }.should raise_error(RangeError) - -> { File.umask(-2**63 - 1) }.should raise_error(RangeError) + -> { File.umask(2**64) }.should.raise(RangeError) + -> { File.umask(-2**63 - 1) }.should.raise(RangeError) end it "raises ArgumentError when more than one argument is provided" do - -> { File.umask(022, 022) }.should raise_error(ArgumentError) + -> { File.umask(022, 022) }.should.raise(ArgumentError) end end diff --git a/spec/ruby/core/file/utime_spec.rb b/spec/ruby/core/file/utime_spec.rb index 03adc76efe..d87626be50 100644 --- a/spec/ruby/core/file/utime_spec.rb +++ b/spec/ruby/core/file/utime_spec.rb @@ -1,83 +1,6 @@ require_relative '../../spec_helper' +require_relative 'shared/update_time' describe "File.utime" do - - before :all do - @time_is_float = /mswin|mingw/ =~ RUBY_PLATFORM && RUBY_VERSION >= '2.5' - end - - before :each do - @atime = Time.now - @mtime = Time.now - @file1 = tmp("specs_file_utime1") - @file2 = tmp("specs_file_utime2") - touch @file1 - touch @file2 - end - - after :each do - rm_r @file1, @file2 - end - - it "sets the access and modification time of each file" do - File.utime(@atime, @mtime, @file1, @file2) - if @time_is_float - File.atime(@file1).should be_close(@atime, 0.0001) - File.mtime(@file1).should be_close(@mtime, 0.0001) - File.atime(@file2).should be_close(@atime, 0.0001) - File.mtime(@file2).should be_close(@mtime, 0.0001) - else - File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE) - File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE) - File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE) - File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE) - end - end - - it "uses the current times if two nil values are passed" do - tn = Time.now - File.utime(nil, nil, @file1, @file2) - if @time_is_float - File.atime(@file1).should be_close(tn, 0.050) - File.mtime(@file1).should be_close(tn, 0.050) - File.atime(@file2).should be_close(tn, 0.050) - File.mtime(@file2).should be_close(tn, 0.050) - else - File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE) - File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE) - File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE) - File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE) - end - end - - it "accepts an object that has a #to_path method" do - File.utime(@atime, @mtime, mock_to_path(@file1), mock_to_path(@file2)) - end - - it "accepts numeric atime and mtime arguments" do - if @time_is_float - File.utime(@atime.to_f, @mtime.to_f, @file1, @file2) - File.atime(@file1).should be_close(@atime, 0.0001) - File.mtime(@file1).should be_close(@mtime, 0.0001) - File.atime(@file2).should be_close(@atime, 0.0001) - File.mtime(@file2).should be_close(@mtime, 0.0001) - else - File.utime(@atime.to_i, @mtime.to_i, @file1, @file2) - File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE) - File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE) - File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE) - File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE) - end - end - - platform_is :linux do - platform_is wordsize: 64 do - it "allows Time instances in the far future to set mtime and atime" do - time = Time.at(1<<44) - File.utime(time, time, @file1) - File.atime(@file1).year.should == 559444 - File.mtime(@file1).year.should == 559444 - end - end - end + it_behaves_like :update_time, :utime end diff --git a/spec/ruby/core/file/world_readable_spec.rb b/spec/ruby/core/file/world_readable_spec.rb index 11b8e67d0b..0f5e0b13d7 100644 --- a/spec/ruby/core/file/world_readable_spec.rb +++ b/spec/ruby/core/file/world_readable_spec.rb @@ -7,6 +7,6 @@ describe "File.world_readable?" do it "returns nil if the file does not exist" do file = rand.to_s + $$.to_s File.should_not.exist?(file) - File.world_readable?(file).should be_nil + File.world_readable?(file).should == nil end end diff --git a/spec/ruby/core/file/world_writable_spec.rb b/spec/ruby/core/file/world_writable_spec.rb index d378cf2eb9..46ba6832f9 100644 --- a/spec/ruby/core/file/world_writable_spec.rb +++ b/spec/ruby/core/file/world_writable_spec.rb @@ -7,6 +7,6 @@ describe "File.world_writable?" do it "returns nil if the file does not exist" do file = rand.to_s + $$.to_s File.should_not.exist?(file) - File.world_writable?(file).should be_nil + File.world_writable?(file).should == nil end end diff --git a/spec/ruby/core/file/zero_spec.rb b/spec/ruby/core/file/zero_spec.rb index 63dd85ee46..01c7505ef2 100644 --- a/spec/ruby/core/file/zero_spec.rb +++ b/spec/ruby/core/file/zero_spec.rb @@ -4,10 +4,4 @@ require_relative '../../shared/file/zero' describe "File.zero?" do it_behaves_like :file_zero, :zero?, File it_behaves_like :file_zero_missing, :zero?, File - - platform_is :solaris do - it "returns false for /dev/null" do - File.zero?('/dev/null').should == true - end - end end |
