diff options
Diffstat (limited to 'spec/ruby/core/dir/shared')
-rw-r--r-- | spec/ruby/core/dir/shared/chroot.rb | 41 | ||||
-rw-r--r-- | spec/ruby/core/dir/shared/closed.rb | 9 | ||||
-rw-r--r-- | spec/ruby/core/dir/shared/delete.rb | 61 | ||||
-rw-r--r-- | spec/ruby/core/dir/shared/exist.rb | 56 | ||||
-rw-r--r-- | spec/ruby/core/dir/shared/glob.rb | 328 | ||||
-rw-r--r-- | spec/ruby/core/dir/shared/open.rb | 63 | ||||
-rw-r--r-- | spec/ruby/core/dir/shared/path.rb | 32 | ||||
-rw-r--r-- | spec/ruby/core/dir/shared/pos.rb | 51 | ||||
-rw-r--r-- | spec/ruby/core/dir/shared/pwd.rb | 49 |
9 files changed, 690 insertions, 0 deletions
diff --git a/spec/ruby/core/dir/shared/chroot.rb b/spec/ruby/core/dir/shared/chroot.rb new file mode 100644 index 0000000000..2ed033dfed --- /dev/null +++ b/spec/ruby/core/dir/shared/chroot.rb @@ -0,0 +1,41 @@ +describe :dir_chroot_as_root, shared: true do + before :all do + DirSpecs.create_mock_dirs + + @real_root = "../" * (File.dirname(__FILE__).count('/') - 1) + @ref_dir = File.join("/", Dir.new('/').entries.first) + end + + after :all do + until File.exist?(@ref_dir) + Dir.send(@method, "../") or break + end + + DirSpecs.delete_mock_dirs + end + + it "can be used to change the process' root directory" do + lambda { Dir.send(@method, File.dirname(__FILE__)) }.should_not raise_error + File.exist?("/#{File.basename(__FILE__)}").should be_true + end + + it "returns 0 if successful" do + Dir.send(@method, '/').should == 0 + end + + it "raises an Errno::ENOENT exception if the directory doesn't exist" do + lambda { Dir.send(@method, 'xgwhwhsjai2222jg') }.should raise_error(Errno::ENOENT) + end + + it "can be escaped from with ../" do + Dir.send(@method, @real_root) + File.exist?(@ref_dir).should be_true + File.exist?("/#{File.basename(__FILE__)}").should be_false + end + + it "calls #to_path on non-String argument" do + p = mock('path') + p.should_receive(:to_path).and_return(@real_root) + Dir.send(@method, p) + end +end diff --git a/spec/ruby/core/dir/shared/closed.rb b/spec/ruby/core/dir/shared/closed.rb new file mode 100644 index 0000000000..a1bce06a08 --- /dev/null +++ b/spec/ruby/core/dir/shared/closed.rb @@ -0,0 +1,9 @@ +describe :dir_closed, shared: true do + it "raises an IOError when called on a closed Dir instance" do + lambda { + dir = Dir.open DirSpecs.mock_dir + dir.close + dir.send(@method) {} + }.should raise_error(IOError) + end +end diff --git a/spec/ruby/core/dir/shared/delete.rb b/spec/ruby/core/dir/shared/delete.rb new file mode 100644 index 0000000000..8db17d985f --- /dev/null +++ b/spec/ruby/core/dir/shared/delete.rb @@ -0,0 +1,61 @@ +describe :dir_delete, shared: true do + before :each do + DirSpecs.rmdir_dirs true + end + + after :each do + DirSpecs.rmdir_dirs false + end + + it "removes empty directories" do + Dir.send(@method, DirSpecs.mock_rmdir("empty")).should == 0 + end + + it "calls #to_path on non-String arguments" do + p = mock('path') + p.should_receive(:to_path).and_return(DirSpecs.mock_rmdir("empty")) + Dir.send(@method, p) + end + + platform_is_not :solaris do + it "raises an Errno::ENOTEMPTY when trying to remove a nonempty directory" do + lambda do + Dir.send @method, DirSpecs.mock_rmdir("nonempty") + end.should raise_error(Errno::ENOTEMPTY) + end + end + + platform_is :solaris do + it "raises an Errno::EEXIST when trying to remove a nonempty directory" do + lambda do + Dir.send @method, DirSpecs.mock_rmdir("nonempty") + end.should raise_error(Errno::EEXIST) + end + end + + it "raises an Errno::ENOENT when trying to remove a non-existing directory" do + lambda do + Dir.send @method, DirSpecs.nonexistent + end.should raise_error(Errno::ENOENT) + end + + it "raises an Errno::ENOTDIR when trying to remove a non-directory" do + file = DirSpecs.mock_rmdir("nonempty/regular") + touch(file) + lambda do + Dir.send @method, file + end.should raise_error(Errno::ENOTDIR) + end + + # this won't work on Windows, since chmod(0000) does not remove all permissions + platform_is_not :windows do + it "raises an Errno::EACCES if lacking adequate permissions to remove the directory" do + parent = DirSpecs.mock_rmdir("noperm") + child = DirSpecs.mock_rmdir("noperm", "child") + File.chmod(0000, parent) + lambda do + Dir.send @method, child + end.should raise_error(Errno::EACCES) + end + end +end diff --git a/spec/ruby/core/dir/shared/exist.rb b/spec/ruby/core/dir/shared/exist.rb new file mode 100644 index 0000000000..fbd2c9862d --- /dev/null +++ b/spec/ruby/core/dir/shared/exist.rb @@ -0,0 +1,56 @@ +describe :dir_exist, shared: true do + it "returns true if the given directory exists" do + Dir.send(@method, File.dirname(__FILE__)).should be_true + end + + it "returns true for '.'" do + Dir.send(@method, '.').should be_true + end + + it "returns true for '..'" do + Dir.send(@method, '..').should be_true + end + + it "understands non-ASCII paths" do + subdir = File.join(tmp("\u{9876}\u{665}")) + Dir.send(@method, subdir).should be_false + Dir.mkdir(subdir) + Dir.send(@method, subdir).should be_true + Dir.rmdir(subdir) + end + + it "understands relative paths" do + Dir.send(@method, File.dirname(__FILE__) + '/../').should be_true + end + + it "returns false if the given directory doesn't exist" do + Dir.send(@method, 'y26dg27n2nwjs8a/').should be_false + end + + it "doesn't require the name to have a trailing slash" do + dir = File.dirname(__FILE__) + dir.sub!(/\/$/,'') + Dir.send(@method, dir).should be_true + end + + it "doesn't expand paths" do + Dir.send(@method, File.expand_path('~')).should be_true + Dir.send(@method, '~').should be_false + end + + it "returns false if the argument exists but is a file" do + File.exist?(__FILE__).should be_true + Dir.send(@method, __FILE__).should be_false + end + + it "doesn't set $! when file doesn't exist" do + Dir.send(@method, "/path/to/non/existent/dir") + $!.should be_nil + end + + it "calls #to_path on non String arguments" do + p = mock('path') + p.should_receive(:to_path).and_return(File.dirname(__FILE__)) + Dir.send(@method, p) + end +end diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb new file mode 100644 index 0000000000..d2201cd6cd --- /dev/null +++ b/spec/ruby/core/dir/shared/glob.rb @@ -0,0 +1,328 @@ +# -*- encoding: utf-8 -*- +describe :dir_glob, shared: true do + before :all do + DirSpecs.create_mock_dirs + @cwd = Dir.pwd + Dir.chdir DirSpecs.mock_dir + end + + after :all do + Dir.chdir @cwd + DirSpecs.delete_mock_dirs + end + + with_feature :encoding do + it "raises an Encoding::CompatibilityError if the argument encoding is not compatible with US-ASCII" do + pattern = "file*".force_encoding Encoding::UTF_16BE + lambda { Dir.send(@method, pattern) }.should raise_error(Encoding::CompatibilityError) + end + end + + it "calls #to_path to convert a pattern" do + obj = mock('file_one.ext') + obj.should_receive(:to_path).and_return('file_one.ext') + + Dir.send(@method, obj).should == %w[file_one.ext] + end + + it "splits the string on \\0 if there is only one string given" do + Dir.send(@method, "file_o*\0file_t*").should == + %w!file_one.ext file_two.ext! + end + + it "matches non-dotfiles with '*'" do + expected = %w[ + brace + deeply + dir + dir_filename_ordering + file_one.ext + file_two.ext + nondotfile + special + subdir_one + subdir_two + ] + + Dir.send(@method,'*').sort.should == expected + end + + it "returns empty array when empty pattern provided" do + Dir.send(@method, '').should == [] + end + + it "matches regexp special +" do + Dir.send(@method, 'special/+').should == ['special/+'] + end + + platform_is_not :windows do + it "matches regexp special *" do + Dir.send(@method, 'special/\*').should == ['special/*'] + end + + it "matches regexp special ?" do + Dir.send(@method, 'special/\?').should == ['special/?'] + end + + it "matches regexp special |" do + Dir.send(@method, 'special/|').should == ['special/|'] + end + end + + it "matches regexp special ^" do + Dir.send(@method, 'special/^').should == ['special/^'] + end + + it "matches regexp special $" do + Dir.send(@method, 'special/$').should == ['special/$'] + end + + it "matches regexp special (" do + Dir.send(@method, 'special/(').should == ['special/('] + end + + it "matches regexp special )" do + Dir.send(@method, 'special/)').should == ['special/)'] + end + + it "matches regexp special [" do + Dir.send(@method, 'special/\[').should == ['special/['] + end + + it "matches regexp special ]" do + Dir.send(@method, 'special/]').should == ['special/]'] + end + + it "matches regexp special {" do + Dir.send(@method, 'special/\{').should == ['special/{'] + end + + it "matches regexp special }" do + Dir.send(@method, 'special/\}').should == ['special/}'] + end + + it "matches paths with glob patterns" do + Dir.send(@method, 'special/test\{1\}/*').should == ['special/test{1}/file[1]'] + end + + it "matches dotfiles with '.*'" do + Dir.send(@method, '.*').sort.should == %w|. .. .dotfile .dotsubdir|.sort + end + + it "matches non-dotfiles with '*<non-special characters>'" do + Dir.send(@method, '*file').sort.should == %w|nondotfile|.sort + end + + it "matches dotfiles with '.*<non-special characters>'" do + Dir.send(@method, '.*file').sort.should == %w|.dotfile|.sort + end + + it "matches files with any ending with '<non-special characters>*'" do + Dir.send(@method, 'file*').sort.should == %w|file_one.ext file_two.ext|.sort + end + + it "matches files with any middle with '<non-special characters>*<non-special characters>'" do + Dir.send(@method, 'sub*_one').sort.should == %w|subdir_one|.sort + end + + it "handles directories with globs" do + Dir.send(@method, 'sub*/*').sort.should == %w!subdir_one/nondotfile subdir_two/nondotfile subdir_two/nondotfile.ext! + end + + it "matches files with multiple '*' special characters" do + Dir.send(@method, '*fi*e*').sort.should == %w|dir_filename_ordering nondotfile file_one.ext file_two.ext|.sort + end + + it "matches non-dotfiles in the current directory with '**'" do + expected = %w[ + brace + deeply + dir + dir_filename_ordering + file_one.ext + file_two.ext + nondotfile + special + subdir_one + subdir_two + ] + + Dir.send(@method, '**').sort.should == expected + end + + it "matches dotfiles in the current directory with '.**'" do + Dir.send(@method, '.**').sort.should == %w|. .. .dotsubdir .dotfile|.sort + end + + it "recursively matches any nondot subdirectories with '**/'" do + expected = %w[ + brace/ + deeply/ + deeply/nested/ + deeply/nested/directory/ + deeply/nested/directory/structure/ + dir/ + special/ + special/test{1}/ + subdir_one/ + subdir_two/ + ] + + Dir.send(@method, '**/').sort.should == expected + end + + it "recursively matches any subdirectories including ./ and ../ with '.**/'" do + Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do + Dir.send(@method, '.**/').sort.should == %w|./ ../|.sort + end + end + + it "matches a single character except leading '.' with '?'" do + Dir.send(@method, '?ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "accepts multiple '?' characters in a pattern" do + Dir.send(@method, 'subdir_???').sort.should == %w|subdir_one subdir_two|.sort + end + + it "matches any characters in a set with '[<characters>]'" do + Dir.send(@method, '[stfu]ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "matches any characters in a range with '[<character>-<character>]'" do + Dir.send(@method, '[a-zA-Z]ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "matches any characters except those in a set with '[^<characters>]'" do + Dir.send(@method, '[^wtf]ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "matches any characters except those in a range with '[^<character>-<character]'" do + Dir.send(@method, '[^0-9]ubdir_one').sort.should == %w|subdir_one|.sort + end + + it "matches any one of the strings in a set with '{<string>,<other>,...}'" do + Dir.send(@method, 'subdir_{one,two,three}').sort.should == %w|subdir_one subdir_two|.sort + end + + it "matches a set '{<string>,<other>,...}' which also uses a glob" do + Dir.send(@method, 'sub*_{one,two,three}').sort.should == %w|subdir_one subdir_two|.sort + end + + it "accepts string sets with empty strings with {<string>,,<other>}" do + a = Dir.send(@method, 'deeply/nested/directory/structure/file_one{.ext,}').sort + a.should == %w|deeply/nested/directory/structure/file_one.ext + deeply/nested/directory/structure/file_one|.sort + end + + it "matches dot or non-dotfiles with '{,.}*'" do + Dir.send(@method, '{,.}*').sort.should == DirSpecs.expected_paths + end + + it "respects the order of {} expressions, expanding left most first" do + files = Dir.send(@method, "brace/a{.js,.html}{.erb,.rjs}") + files.should == %w!brace/a.js.rjs brace/a.html.erb! + end + + it "respects the optional nested {} expressions" do + files = Dir.send(@method, "brace/a{.{js,html},}{.{erb,rjs},}") + files.should == %w!brace/a.js.rjs brace/a.js brace/a.html.erb brace/a.erb brace/a! + end + + it "matches special characters by escaping with a backslash with '\\<character>'" do + Dir.mkdir 'foo^bar' + + begin + Dir.send(@method, 'foo?bar').should == %w|foo^bar| + Dir.send(@method, 'foo\?bar').should == [] + Dir.send(@method, 'nond\otfile').should == %w|nondotfile| + ensure + Dir.rmdir 'foo^bar' + end + end + + it "recursively matches directories with '**/<characters>'" do + Dir.send(@method, '**/*fil?{,.}*').uniq.sort.should == + %w[deeply/nested/directory/structure/file_one + deeply/nested/directory/structure/file_one.ext + deeply/nondotfile + + dir/filename_ordering + dir_filename_ordering + + file_one.ext + file_two.ext + + nondotfile + + special/test{1}/file[1] + + subdir_one/nondotfile + subdir_two/nondotfile + subdir_two/nondotfile.ext] + end + + it "ignores matching through directories that doen't exist" do + Dir.send(@method, "deeply/notthere/blah*/whatever").should == [] + end + + it "ignores matching only directories under an nonexistant path" do + Dir.send(@method, "deeply/notthere/blah/").should == [] + end + + platform_is_not :windows do + it "matches UTF-8 paths" do + Dir.send(@method, "special/こんにちは{,.txt}").should == ["special/こんにちは.txt"] + end + end +end + +describe :dir_glob_recursive, shared: true do + before :each do + @cwd = Dir.pwd + @mock_dir = File.expand_path tmp('dir_glob_mock') + + %w[ + a/x/b/y/e + a/x/b/y/b/z/e + ].each do |path| + file = File.join @mock_dir, path + mkdir_p File.dirname(file) + touch file + end + + Dir.chdir @mock_dir + end + + after :each do + Dir.chdir @cwd + rm_r @mock_dir + end + + it "matches multiple recursives" do + expected = %w[ + a/x/b/y/b/z/e + a/x/b/y/e + ] + + Dir.send(@method, 'a/**/b/**/e').uniq.sort.should == expected + end + + platform_is_not :windows do + it "ignores symlinks" do + file = File.join @mock_dir, 'b/z/e' + link = File.join @mock_dir, 'a/y' + + mkdir_p File.dirname(file) + touch file + File.symlink(File.dirname(file), link) + + expected = %w[ + a/x/b/y/b/z/e + a/x/b/y/e + ] + + Dir.send(@method, 'a/**/e').uniq.sort.should == expected + end + end +end diff --git a/spec/ruby/core/dir/shared/open.rb b/spec/ruby/core/dir/shared/open.rb new file mode 100644 index 0000000000..3c2b63b6fa --- /dev/null +++ b/spec/ruby/core/dir/shared/open.rb @@ -0,0 +1,63 @@ +describe :dir_open, shared: true do + it "returns a Dir instance representing the specified directory" do + dir = Dir.send(@method, DirSpecs.mock_dir) + dir.should be_kind_of(Dir) + dir.close + end + + it "raises a SystemCallError if the directory does not exist" do + lambda do + Dir.send @method, DirSpecs.nonexistent + end.should raise_error(SystemCallError) + end + + it "may take a block which is yielded to with the Dir instance" do + Dir.send(@method, DirSpecs.mock_dir) {|dir| dir.should be_kind_of(Dir)} + end + + it "returns the value of the block if a block is given" do + Dir.send(@method, DirSpecs.mock_dir) {|dir| :value }.should == :value + end + + it "closes the Dir instance when the block exits if given a block" do + closed_dir = Dir.send(@method, DirSpecs.mock_dir) { |dir| dir } + lambda { closed_dir.read }.should raise_error(IOError) + end + + it "closes the Dir instance when the block exits the block even due to an exception" do + closed_dir = nil + + lambda do + Dir.send(@method, DirSpecs.mock_dir) do |dir| + closed_dir = dir + raise + end + end.should raise_error + + lambda { closed_dir.read }.should raise_error(IOError) + end + + it "calls #to_path on non-String arguments" do + p = mock('path') + p.should_receive(:to_path).and_return(DirSpecs.mock_dir) + Dir.send(@method, p) { true } + end + + it "accepts an options Hash" do + dir = Dir.send(@method, DirSpecs.mock_dir, encoding: "utf-8") {|d| d } + dir.should be_kind_of(Dir) + end + + it "calls #to_hash to convert the options object" do + options = mock("dir_open") + options.should_receive(:to_hash).and_return({ encoding: Encoding::UTF_8 }) + + dir = Dir.send(@method, DirSpecs.mock_dir, options) {|d| d } + dir.should be_kind_of(Dir) + end + + it "ignores the :encoding option if it is nil" do + dir = Dir.send(@method, DirSpecs.mock_dir, encoding: nil) {|d| d } + dir.should be_kind_of(Dir) + end +end diff --git a/spec/ruby/core/dir/shared/path.rb b/spec/ruby/core/dir/shared/path.rb new file mode 100644 index 0000000000..829eeb04c2 --- /dev/null +++ b/spec/ruby/core/dir/shared/path.rb @@ -0,0 +1,32 @@ +require File.expand_path('../../../../spec_helper', __FILE__) +require File.expand_path('../../fixtures/common', __FILE__) +require File.expand_path('../closed', __FILE__) + +describe :dir_path, shared: true do + it "returns the path that was supplied to .new or .open" do + dir = Dir.open DirSpecs.mock_dir + begin + dir.send(@method).should == DirSpecs.mock_dir + ensure + dir.close rescue nil + end + end + + it "returns the path even when called on a closed Dir instance" do + dir = Dir.open DirSpecs.mock_dir + dir.close + dir.send(@method).should == DirSpecs.mock_dir + end + + with_feature :encoding do + it "returns a String with the same encoding as the argument to .open" do + path = DirSpecs.mock_dir.force_encoding Encoding::IBM866 + dir = Dir.open path + begin + dir.send(@method).encoding.should equal(Encoding::IBM866) + ensure + dir.close + end + end + end +end diff --git a/spec/ruby/core/dir/shared/pos.rb b/spec/ruby/core/dir/shared/pos.rb new file mode 100644 index 0000000000..2165932d99 --- /dev/null +++ b/spec/ruby/core/dir/shared/pos.rb @@ -0,0 +1,51 @@ +describe :dir_pos, shared: true do + before :each do + @dir = Dir.open DirSpecs.mock_dir + end + + after :each do + @dir.close rescue nil + end + + it "returns an Integer representing the current position in the directory" do + @dir.send(@method).should be_kind_of(Integer) + @dir.send(@method).should be_kind_of(Integer) + @dir.send(@method).should be_kind_of(Integer) + end + + it "returns a different Integer if moved from previous position" do + a = @dir.send(@method) + @dir.read + b = @dir.send(@method) + + a.should be_kind_of(Integer) + b.should be_kind_of(Integer) + + a.should_not == b + end +end + +describe :dir_pos_set, shared: true do + before :each do + @dir = Dir.open DirSpecs.mock_dir + end + + after :each do + @dir.close + end + + # NOTE: #seek/#pos= to a position not returned by #tell/#pos is undefined + # and should not be spec'd. + + it "moves the read position to a previously obtained position" do + pos = @dir.pos + a = @dir.read + b = @dir.read + @dir.send @method, pos + c = @dir.read + + a.should_not == b + b.should_not == c + c.should == a + end +end diff --git a/spec/ruby/core/dir/shared/pwd.rb b/spec/ruby/core/dir/shared/pwd.rb new file mode 100644 index 0000000000..5f041a9d41 --- /dev/null +++ b/spec/ruby/core/dir/shared/pwd.rb @@ -0,0 +1,49 @@ +describe :dir_pwd, shared: true do + with_feature :encoding do + before :each do + @fs_encoding = Encoding.find('filesystem') + end + end + + it "returns the current working directory" do + pwd = Dir.send(@method) + + File.directory?(pwd).should == true + + # On ubuntu gutsy, for example, /bin/pwd does not + # understand -P. With just `pwd -P`, /bin/pwd is run. + + # The following uses inode rather than file names to account for + # case insensitive file systems like default OS/X file systems + platform_is_not :windows do + File.stat(pwd).ino.should == File.stat(`/bin/sh -c "pwd -P"`.chomp).ino + end + platform_is :windows do + File.stat(pwd).ino.should == File.stat(File.expand_path(`cd`.chomp)).ino + end + end + + it "returns an absolute path" do + pwd = Dir.send(@method) + pwd.should == File.expand_path(pwd) + end + + it "returns an absolute path even when chdir to a relative path" do + Dir.chdir(".") do + pwd = Dir.send(@method) + File.directory?(pwd).should == true + pwd.should == File.expand_path(pwd) + end + end + + with_feature :encoding do + it "returns a String with the filesystem encoding" do + enc = Dir.send(@method).encoding + if @fs_encoding == Encoding::US_ASCII + [Encoding::US_ASCII, Encoding::ASCII_8BIT].should include(enc) + else + enc.should equal(@fs_encoding) + end + end + end +end |