diff options
Diffstat (limited to 'spec/ruby/core/file/shared')
| -rw-r--r-- | spec/ruby/core/file/shared/fnmatch.rb | 241 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/open.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/path.rb | 92 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/read.rb | 8 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/stat.rb | 6 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/unlink.rb | 61 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/update_time.rb | 105 |
7 files changed, 113 insertions, 402 deletions
diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb deleted file mode 100644 index a8488fd30a..0000000000 --- a/spec/ruby/core/file/shared/fnmatch.rb +++ /dev/null @@ -1,241 +0,0 @@ -describe :file_fnmatch, shared: true do - it "matches entire strings" do - File.send(@method, 'cat', 'cat').should == true - end - - it "does not match partial strings" do - File.send(@method, 'cat', 'category').should == false - end - - it "does not support { } patterns by default" do - File.send(@method, 'c{at,ub}s', 'cats').should == false - File.send(@method, 'c{at,ub}s', 'c{at,ub}s').should == true - end - - it "supports some { } patterns when File::FNM_EXTGLOB is passed" do - File.send(@method, "{a,b}", "a", File::FNM_EXTGLOB).should == true - File.send(@method, "{a,b}", "b", File::FNM_EXTGLOB).should == true - File.send(@method, "c{at,ub}s", "cats", File::FNM_EXTGLOB).should == true - File.send(@method, "c{at,ub}s", "cubs", File::FNM_EXTGLOB).should == true - File.send(@method, "-c{at,ub}s-", "-cats-", File::FNM_EXTGLOB).should == true - File.send(@method, "-c{at,ub}s-", "-cubs-", File::FNM_EXTGLOB).should == true - File.send(@method, "{a,b,c}{d,e,f}{g,h}", "adg", File::FNM_EXTGLOB).should == true - File.send(@method, "{a,b,c}{d,e,f}{g,h}", "bdg", File::FNM_EXTGLOB).should == true - File.send(@method, "{a,b,c}{d,e,f}{g,h}", "ceh", File::FNM_EXTGLOB).should == true - File.send(@method, "{aa,bb,cc,dd}", "aa", File::FNM_EXTGLOB).should == true - File.send(@method, "{aa,bb,cc,dd}", "bb", File::FNM_EXTGLOB).should == true - File.send(@method, "{aa,bb,cc,dd}", "cc", File::FNM_EXTGLOB).should == true - File.send(@method, "{aa,bb,cc,dd}", "dd", File::FNM_EXTGLOB).should == true - File.send(@method, "{1,5{a,b{c,d}}}", "1", File::FNM_EXTGLOB).should == true - File.send(@method, "{1,5{a,b{c,d}}}", "5a", File::FNM_EXTGLOB).should == true - File.send(@method, "{1,5{a,b{c,d}}}", "5bc", File::FNM_EXTGLOB).should == true - File.send(@method, "{1,5{a,b{c,d}}}", "5bd", File::FNM_EXTGLOB).should == true - File.send(@method, "\\\\{a\\,b,b\\}c}", "\\a,b", File::FNM_EXTGLOB).should == true - File.send(@method, "\\\\{a\\,b,b\\}c}", "\\b}c", File::FNM_EXTGLOB).should == true - end - - it "doesn't support some { } patterns even when File::FNM_EXTGLOB is passed" do - File.send(@method, "a{0..3}b", "a0b", File::FNM_EXTGLOB).should == false - File.send(@method, "a{0..3}b", "a1b", File::FNM_EXTGLOB).should == false - File.send(@method, "a{0..3}b", "a2b", File::FNM_EXTGLOB).should == false - File.send(@method, "a{0..3}b", "a3b", File::FNM_EXTGLOB).should == false - File.send(@method, "{0..12}", "0", File::FNM_EXTGLOB).should == false - File.send(@method, "{0..12}", "6", File::FNM_EXTGLOB).should == false - File.send(@method, "{0..12}", "12", File::FNM_EXTGLOB).should == false - File.send(@method, "{3..-2}", "3", File::FNM_EXTGLOB).should == false - File.send(@method, "{3..-2}", "0", File::FNM_EXTGLOB).should == false - File.send(@method, "{3..-2}", "-2", File::FNM_EXTGLOB).should == false - File.send(@method, "{a..g}", "a", File::FNM_EXTGLOB).should == false - File.send(@method, "{a..g}", "d", File::FNM_EXTGLOB).should == false - File.send(@method, "{a..g}", "g", File::FNM_EXTGLOB).should == false - File.send(@method, "{g..a}", "a", File::FNM_EXTGLOB).should == false - File.send(@method, "{g..a}", "d", File::FNM_EXTGLOB).should == false - File.send(@method, "{g..a}", "g", File::FNM_EXTGLOB).should == false - File.send(@method, "escaping: {{,\\,,\\},\\{}", "escaping: {", File::FNM_EXTGLOB).should == false - File.send(@method, "escaping: {{,\\,,\\},\\{}", "escaping: ,", File::FNM_EXTGLOB).should == false - File.send(@method, "escaping: {{,\\,,\\},\\{}", "escaping: }", File::FNM_EXTGLOB).should == false - File.send(@method, "escaping: {{,\\,,\\},\\{}", "escaping: {", File::FNM_EXTGLOB).should == false - end - - it "doesn't match an extra } when File::FNM_EXTGLOB is passed" do - File.send(@method, 'c{at,ub}}s', 'cats', File::FNM_EXTGLOB).should == false - end - - it "matches when both FNM_EXTGLOB and FNM_PATHNAME are passed" do - File.send(@method, "?.md", "a.md", File::FNM_EXTGLOB | File::FNM_PATHNAME).should == true - end - - it "matches a single character for each ? character" do - File.send(@method, 'c?t', 'cat').should == true - File.send(@method, 'c??t', 'cat').should == false - end - - it "matches zero or more characters for each * character" do - File.send(@method, 'c*', 'cats').should == true - File.send(@method, 'c*t', 'c/a/b/t').should == true - end - - it "matches ranges of characters using bracket expression (e.g. [a-z])" do - File.send(@method, 'ca[a-z]', 'cat').should == true - end - - it "matches ranges of characters using bracket expression, taking case into account" do - File.send(@method, '[a-z]', 'D').should == false - File.send(@method, '[^a-z]', 'D').should == true - File.send(@method, '[A-Z]', 'd').should == false - File.send(@method, '[^A-Z]', 'd').should == true - File.send(@method, '[a-z]', 'D', File::FNM_CASEFOLD).should == true - end - - it "does not match characters outside of the range of the bracket expression" do - File.send(@method, 'ca[x-z]', 'cat').should == false - File.send(@method, '/ca[s][s-t]/rul[a-b]/[z]he/[x-Z]orld', '/cats/rule/the/World').should == false - end - - 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]', 'cat').should == false - end - - it "matches characters with a case sensitive comparison" do - File.send(@method, 'cat', 'CAT').should == false - end - - it "matches characters with case insensitive comparison when flags includes FNM_CASEFOLD" do - File.send(@method, 'cat', 'CAT', File::FNM_CASEFOLD).should == true - end - - platform_is_not :windows do - it "doesn't match case sensitive characters on platforms with case sensitive paths, when flags include FNM_SYSCASE" do - File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == false - end - end - - platform_is :windows do - it "matches case sensitive characters on platforms with case insensitive paths, when flags include FNM_SYSCASE" do - File.send(@method, 'cat', 'CAT', File::FNM_SYSCASE).should == true - end - 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 - end - - it "does not match '/' characters inside bracket expressions when flags includes FNM_PATHNAME" do - File.send(@method, '[/]', '/', File::FNM_PATHNAME).should == false - end - - it "matches literal ? or * in path when pattern includes \\? or \\*" do - File.send(@method, '\?', '?').should == true - File.send(@method, '\?', 'a').should == false - - File.send(@method, '\*', '*').should == true - File.send(@method, '\*', 'a').should == false - end - - it "matches literal character (e.g. 'a') in path when pattern includes escaped character (e.g. \\a)" do - File.send(@method, '\a', 'a').should == true - File.send(@method, 'this\b', 'thisb').should == true - end - - it "matches '\\' characters in path when flags includes FNM_NOESACPE" do - File.send(@method, '\a', '\a', File::FNM_NOESCAPE).should == true - File.send(@method, '\a', 'a', File::FNM_NOESCAPE).should == false - File.send(@method, '\[foo\]\[bar\]', '[foo][bar]', File::FNM_NOESCAPE).should == false - end - - it "escapes special characters inside bracket expression" do - File.send(@method, '[\?]', '?').should == true - File.send(@method, '[\*]', '*').should == true - 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 - end - - it "matches patterns with leading periods to dotfiles by default" do - File.send(@method, '.*', '.profile').should == true - File.send(@method, ".*file", "nondotfile").should == false - end - - it "matches leading periods in filenames when flags includes FNM_DOTMATCH" do - File.send(@method, '*', '.profile', File::FNM_DOTMATCH).should == true - File.send(@method, '*', 'home/.profile', File::FNM_DOTMATCH).should == true - end - - it "matches multiple directories with ** and *" do - files = '**/*.rb' - File.send(@method, files, 'main.rb').should == false - File.send(@method, files, './main.rb').should == false - File.send(@method, files, 'lib/song.rb').should == true - File.send(@method, '**.rb', 'main.rb').should == true - File.send(@method, '**.rb', './main.rb').should == false - File.send(@method, '**.rb', 'lib/song.rb').should == true - File.send(@method, '*', 'dave/.profile').should == true - end - - it "matches multiple directories with ** when flags includes File::FNM_PATHNAME" do - files = '**/*.rb' - flags = File::FNM_PATHNAME - - File.send(@method, files, 'main.rb', flags).should == true - File.send(@method, files, 'one/two/three/main.rb', flags).should == true - File.send(@method, files, './main.rb', flags).should == false - - flags = File::FNM_PATHNAME | File::FNM_DOTMATCH - - File.send(@method, files, './main.rb', flags).should == true - File.send(@method, files, 'one/two/.main.rb', flags).should == true - - File.send(@method, "**/best/*", 'lib/my/best/song.rb').should == true - end - - 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 - - pattern = '**/foo' - File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME).should be_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 - - 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 - end - - it "accepts an object that has a #to_path method" do - File.send(@method, '\*', mock_to_path('a')).should == false - 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) - 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) - 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 - end - - it "matches multibyte characters" do - File.fnmatch("*/ä/ø/ñ", "a/ä/ø/ñ").should == true - end -end 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 deleted file mode 100644 index 0a5abe33f0..0000000000 --- a/spec/ruby/core/file/shared/path.rb +++ /dev/null @@ -1,92 +0,0 @@ -describe :file_path, shared: true do - before :each do - @name = "file_to_path" - @path = tmp(@name) - touch @path - end - - after :each do - @file.close if @file and !@file.closed? - rm_r @path - end - - it "returns a String" do - @file = File.new @path - @file.send(@method).should be_an_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 - path = mock('path') - path.should_receive(:to_str).and_return(@path) - @file = File.new path - @file.send(@method).should == @path - end - - it "does not normalise the path it returns" do - Dir.chdir(tmp("")) do - unorm = "./#{@name}" - @file = File.new unorm - @file.send(@method).should == unorm - end - end - - it "does not canonicalize the path it returns" do - dir = File.basename tmp("") - path = "#{tmp("")}../#{dir}/#{@name}" - @file = File.new path - @file.send(@method).should == path - end - - it "does not absolute-ise the path it returns" do - Dir.chdir(tmp("")) do - @file = File.new @name - @file.send(@method).should == @name - end - end - - it "preserves the encoding of the path" do - path = @path.force_encoding("euc-jp") - @file = File.new path - @file.send(@method).encoding.should == Encoding.find("euc-jp") - end - - 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 - - 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 - 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 deleted file mode 100644 index e339e93271..0000000000 --- a/spec/ruby/core/file/shared/unlink.rb +++ /dev/null @@ -1,61 +0,0 @@ -describe :file_unlink, shared: true do - before :each do - @file1 = tmp('test.txt') - @file2 = tmp('test2.txt') - - touch @file1 - touch @file2 - end - - after :each do - File.send(@method, @file1) if File.exist?(@file1) - File.send(@method, @file2) if File.exist?(@file2) - - @file1 = nil - @file2 = nil - end - - it "returns 0 when called without arguments" do - File.send(@method).should == 0 - end - - it "deletes a single file" do - File.send(@method, @file1).should == 1 - File.should_not.exist?(@file1) - end - - it "deletes multiple files" do - File.send(@method, @file1, @file2).should == 2 - File.should_not.exist?(@file1) - File.should_not.exist?(@file2) - end - - it "raises a TypeError if not passed a String type" do - -> { File.send(@method, 1) }.should raise_error(TypeError) - end - - it "raises an Errno::ENOENT when the given file doesn't exist" do - -> { File.send(@method, 'bogus') }.should raise_error(Errno::ENOENT) - end - - it "coerces a given parameter into a string if possible" do - mock = mock("to_str") - mock.should_receive(:to_str).and_return(@file1) - File.send(@method, mock).should == 1 - end - - it "accepts an object that has a #to_path method" do - File.send(@method, mock_to_path(@file1)).should == 1 - end - - platform_is :windows do - it "allows deleting an open file with File::SHARE_DELETE" do - path = tmp("share_delete.txt") - File.open(path, mode: File::CREAT | File::WRONLY | File::BINARY | File::SHARE_DELETE) do |f| - File.should.exist?(path) - File.send(@method, path) - end - File.should_not.exist?(path) - end - end -end 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 |
