diff options
Diffstat (limited to 'spec/ruby/core/file/shared')
| -rw-r--r-- | spec/ruby/core/file/shared/fnmatch.rb | 91 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/open.rb | 2 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/path.rb | 16 | ||||
| -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 | 4 | ||||
| -rw-r--r-- | spec/ruby/core/file/shared/update_time.rb | 105 |
7 files changed, 190 insertions, 42 deletions
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 0a5abe33f0..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,7 @@ 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 @@ -77,16 +77,6 @@ describe :file_path, shared: true do 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 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 |
