Merge remote branch 'smt/hard_links_and_deletion'
This commit is contained in:
commit
e4ea7e1406
7
Rakefile
7
Rakefile
@ -1,7 +1,10 @@
|
||||
task :default do
|
||||
Dir['test/*_test.rb'].each { |file| require file }
|
||||
desc "Run tests"
|
||||
task :test do
|
||||
Dir['test/**/*_test.rb'].each { |file| require file }
|
||||
end
|
||||
|
||||
task :default => :test
|
||||
|
||||
begin
|
||||
require 'jeweler'
|
||||
|
||||
|
@ -33,5 +33,13 @@ module FakeFS
|
||||
name
|
||||
end
|
||||
end
|
||||
|
||||
def delete(node = self)
|
||||
if node == self
|
||||
parent.delete(self)
|
||||
else
|
||||
super(node.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,16 +1,54 @@
|
||||
module FakeFS
|
||||
class FakeFile
|
||||
attr_accessor :name, :parent, :content
|
||||
attr_accessor :name, :parent
|
||||
|
||||
class Inode
|
||||
def initialize(file_owner)
|
||||
@content = ""
|
||||
@links = [file_owner]
|
||||
end
|
||||
|
||||
attr_accessor :content
|
||||
attr_accessor :links
|
||||
|
||||
def link(file)
|
||||
links << file unless links.include?(file)
|
||||
file.inode = self
|
||||
end
|
||||
|
||||
def unlink(file)
|
||||
links.delete(file)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(name = nil, parent = nil)
|
||||
@name = name
|
||||
@name = name
|
||||
@parent = parent
|
||||
@content = ''
|
||||
@inode = Inode.new(self)
|
||||
end
|
||||
|
||||
attr_accessor :inode
|
||||
|
||||
def content
|
||||
@inode.content
|
||||
end
|
||||
|
||||
def content=(str)
|
||||
@inode.content = str
|
||||
end
|
||||
|
||||
def links
|
||||
@inode.links
|
||||
end
|
||||
|
||||
def link(other_file)
|
||||
@inode.link(other_file)
|
||||
end
|
||||
|
||||
def clone(parent = nil)
|
||||
clone = super()
|
||||
clone.parent = parent if parent
|
||||
clone.inode = inode.clone
|
||||
clone
|
||||
end
|
||||
|
||||
@ -25,5 +63,10 @@ module FakeFS
|
||||
def to_s
|
||||
File.join(parent.to_s, name)
|
||||
end
|
||||
|
||||
def delete
|
||||
inode.unlink(self)
|
||||
parent.delete(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -15,12 +15,18 @@ module FakeFS
|
||||
FileSystem.find(target)
|
||||
end
|
||||
|
||||
def method_missing(*args, &block)
|
||||
entry.send(*args, &block)
|
||||
def delete
|
||||
parent.delete(self)
|
||||
end
|
||||
|
||||
def respond_to?(method)
|
||||
entry.respond_to?(method)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def method_missing(*args, &block)
|
||||
entry.send(*args, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,6 +2,31 @@ module FakeFS
|
||||
class File
|
||||
PATH_SEPARATOR = '/'
|
||||
|
||||
MODES = [
|
||||
READ_ONLY = "r",
|
||||
READ_WRITE = "r+",
|
||||
WRITE_ONLY = "w",
|
||||
READ_WRITE_TRUNCATE = "w+",
|
||||
APPEND_WRITE_ONLY = "a",
|
||||
APPEND_READ_WRITE = "a+"
|
||||
]
|
||||
|
||||
FILE_CREATION_MODES = MODES - [READ_ONLY, READ_WRITE]
|
||||
|
||||
READ_ONLY_MODES = [
|
||||
READ_ONLY
|
||||
]
|
||||
|
||||
WRITE_ONLY_MODES = [
|
||||
WRITE_ONLY,
|
||||
APPEND_WRITE_ONLY
|
||||
]
|
||||
|
||||
TRUNCATION_MODES = [
|
||||
WRITE_ONLY,
|
||||
READ_WRITE_TRUNCATE
|
||||
]
|
||||
|
||||
def self.extname(path)
|
||||
RealFile.extname(path)
|
||||
end
|
||||
@ -69,7 +94,7 @@ module FakeFS
|
||||
FileSystem.find(symlink.target).to_s
|
||||
end
|
||||
|
||||
def self.open(path, mode='r', perm = 0644)
|
||||
def self.open(path, mode=READ_ONLY, perm = 0644)
|
||||
if block_given?
|
||||
yield new(path, mode, perm)
|
||||
else
|
||||
@ -90,12 +115,85 @@ module FakeFS
|
||||
read(path).split("\n")
|
||||
end
|
||||
|
||||
def self.link(source, dest)
|
||||
if directory?(source)
|
||||
raise Errno::EPERM, "Operation not permitted - #{source} or #{dest}"
|
||||
end
|
||||
|
||||
if !exists?(source)
|
||||
raise Errno::ENOENT, "No such file or directory - #{source} or #{dest}"
|
||||
end
|
||||
|
||||
if exists?(dest)
|
||||
raise Errno::EEXIST, "File exists - #{source} or #{dest}"
|
||||
end
|
||||
|
||||
source = FileSystem.find(source)
|
||||
dest = FileSystem.add(dest, source.entry.clone)
|
||||
source.link(dest)
|
||||
|
||||
0
|
||||
end
|
||||
|
||||
def self.delete(file_name, *additional_file_names)
|
||||
if !exists?(file_name)
|
||||
raise Errno::ENOENT, "No such file or directory - #{file_name}"
|
||||
end
|
||||
|
||||
FileUtils.rm(file_name)
|
||||
|
||||
additional_file_names.each do |file_name|
|
||||
FileUtils.rm(file_name)
|
||||
end
|
||||
|
||||
additional_file_names.size + 1
|
||||
end
|
||||
|
||||
class << self
|
||||
alias_method :unlink, :delete
|
||||
end
|
||||
|
||||
def self.symlink(source, dest)
|
||||
FileUtils.ln_s(source, dest)
|
||||
end
|
||||
|
||||
def self.stat(file)
|
||||
File::Stat.new(file)
|
||||
end
|
||||
|
||||
class Stat
|
||||
def initialize(file)
|
||||
if !File.exists?(file)
|
||||
raise(Errno::ENOENT, "No such file or directory - #{file}")
|
||||
end
|
||||
|
||||
@file = file
|
||||
end
|
||||
|
||||
def symlink?
|
||||
File.symlink?(@file)
|
||||
end
|
||||
|
||||
def directory?
|
||||
File.directory?(@file)
|
||||
end
|
||||
|
||||
def nlink
|
||||
FileSystem.find(@file).links.size
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :path
|
||||
def initialize(path, mode = nil, perm = nil)
|
||||
|
||||
def initialize(path, mode = READ_ONLY, perm = nil)
|
||||
@path = path
|
||||
@mode = mode
|
||||
@file = FileSystem.find(path)
|
||||
@open = true
|
||||
|
||||
check_valid_mode
|
||||
file_creation_mode? ? create_missing_file : check_file_existence!
|
||||
truncate_file if truncation_mode?
|
||||
end
|
||||
|
||||
def close
|
||||
@ -103,7 +201,9 @@ module FakeFS
|
||||
end
|
||||
|
||||
def read
|
||||
raise IOError.new('closed stream') unless @open
|
||||
raise IOError, 'closed stream' unless @open
|
||||
raise IOError, 'not opened for reading' if write_only?
|
||||
|
||||
@file.content
|
||||
end
|
||||
|
||||
@ -118,11 +218,8 @@ module FakeFS
|
||||
end
|
||||
|
||||
def write(content)
|
||||
raise IOError.new('closed stream') unless @open
|
||||
|
||||
if !File.exists?(@path)
|
||||
@file = FileSystem.add(path, FakeFile.new)
|
||||
end
|
||||
raise IOError, 'closed stream' unless @open
|
||||
raise IOError, 'not open for writing' if read_only?
|
||||
|
||||
@file.content += content
|
||||
end
|
||||
@ -130,5 +227,49 @@ module FakeFS
|
||||
alias_method :<<, :write
|
||||
|
||||
def flush; self; end
|
||||
|
||||
private
|
||||
|
||||
def check_file_existence!
|
||||
unless @file
|
||||
raise Errno::ENOENT, "No such file or directory - #{@file}"
|
||||
end
|
||||
end
|
||||
|
||||
def check_valid_mode
|
||||
if !mode_in?(MODES)
|
||||
raise ArgumentError, "illegal access mode #{@mode}"
|
||||
end
|
||||
end
|
||||
|
||||
def read_only?
|
||||
mode_in? READ_ONLY_MODES
|
||||
end
|
||||
|
||||
def file_creation_mode?
|
||||
mode_in? FILE_CREATION_MODES
|
||||
end
|
||||
|
||||
def write_only?
|
||||
mode_in? WRITE_ONLY_MODES
|
||||
end
|
||||
|
||||
def truncation_mode?
|
||||
mode_in? TRUNCATION_MODES
|
||||
end
|
||||
|
||||
def mode_in?(list)
|
||||
list.include?(@mode)
|
||||
end
|
||||
|
||||
def create_missing_file
|
||||
if !File.exists?(@path)
|
||||
@file = FileSystem.add(path, FakeFile.new)
|
||||
end
|
||||
end
|
||||
|
||||
def truncate_file
|
||||
@file.content = ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -54,7 +54,7 @@ module FakeFS
|
||||
files.each do |f|
|
||||
if RealFile.file?(f)
|
||||
FileUtils.mkdir_p(File.dirname(f))
|
||||
File.open(f, 'w') do |g|
|
||||
File.open(f, File::WRITE_ONLY) do |g|
|
||||
g.print RealFile.open(f){|h| h.read }
|
||||
end
|
||||
elsif RealFile.directory?(f)
|
||||
@ -66,8 +66,8 @@ module FakeFS
|
||||
end
|
||||
|
||||
def delete(path)
|
||||
if dir = FileSystem.find(path)
|
||||
dir.parent.delete(dir.name)
|
||||
if node = FileSystem.find(path)
|
||||
node.delete
|
||||
end
|
||||
end
|
||||
|
||||
|
88
test/fake/file_test.rb
Normal file
88
test/fake/file_test.rb
Normal file
@ -0,0 +1,88 @@
|
||||
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
||||
require 'fakefs/safe'
|
||||
require 'test/unit'
|
||||
|
||||
class FakeFileTest < Test::Unit::TestCase
|
||||
include FakeFS
|
||||
|
||||
def setup
|
||||
FileSystem.clear
|
||||
|
||||
@file = FakeFile.new
|
||||
end
|
||||
|
||||
def test_fake_file_has_empty_content_by_default
|
||||
assert_equal "", @file.content
|
||||
end
|
||||
|
||||
def test_fake_file_can_read_and_write_to_content
|
||||
@file.content = "foobar"
|
||||
assert_equal "foobar", @file.content
|
||||
end
|
||||
|
||||
def test_fake_file_has_1_link_by_default
|
||||
assert_equal [@file], @file.links
|
||||
end
|
||||
|
||||
def test_fake_file_can_create_link
|
||||
other_file = FakeFile.new
|
||||
|
||||
@file.link(other_file)
|
||||
|
||||
assert_equal [@file, other_file], @file.links
|
||||
end
|
||||
|
||||
def test_fake_file_wont_add_link_to_same_file_twice
|
||||
other_file = FakeFile.new
|
||||
|
||||
@file.link other_file
|
||||
@file.link other_file
|
||||
|
||||
assert_equal [@file, other_file], @file.links
|
||||
end
|
||||
|
||||
def test_links_are_mutual
|
||||
other_file = FakeFile.new
|
||||
|
||||
@file.link(other_file)
|
||||
|
||||
assert_equal [@file, other_file], other_file.links
|
||||
end
|
||||
|
||||
def test_can_link_multiple_files
|
||||
file_two = FakeFile.new
|
||||
file_three = FakeFile.new
|
||||
|
||||
@file.link file_two
|
||||
@file.link file_three
|
||||
|
||||
assert_equal [@file, file_two, file_three], @file.links
|
||||
assert_equal [@file, file_two, file_three], file_two.links
|
||||
assert_equal [@file, file_two, file_three], file_three.links
|
||||
end
|
||||
|
||||
def test_links_share_same_content
|
||||
other_file = FakeFile.new
|
||||
|
||||
@file.link other_file
|
||||
|
||||
@file.content = "foobar"
|
||||
|
||||
assert_equal "foobar", other_file.content
|
||||
end
|
||||
|
||||
def test_clone_creates_new_inode
|
||||
clone = @file.clone
|
||||
assert !clone.inode.equal?(@file.inode)
|
||||
end
|
||||
|
||||
def test_cloning_does_not_use_same_content_object
|
||||
clone = @file.clone
|
||||
|
||||
clone.content = "foo"
|
||||
@file.content = "bar"
|
||||
|
||||
assert_equal "foo", clone.content
|
||||
assert_equal "bar", @file.content
|
||||
end
|
||||
end
|
11
test/fake/symlink_test.rb
Normal file
11
test/fake/symlink_test.rb
Normal file
@ -0,0 +1,11 @@
|
||||
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
||||
require 'fakefs/safe'
|
||||
require 'test/unit'
|
||||
|
||||
class FakeSymlinkTest < Test::Unit::TestCase
|
||||
include FakeFS
|
||||
|
||||
def test_symlink_has_method_missing_as_private
|
||||
assert FakeSymlink.private_instance_methods.include?("method_missing")
|
||||
end
|
||||
end
|
@ -96,6 +96,92 @@ class FakeFSTest < Test::Unit::TestCase
|
||||
assert File.exists?(path)
|
||||
end
|
||||
|
||||
def test_file_opens_in_read_only_mode
|
||||
File.open("foo", "w") { |f| f << "foo" }
|
||||
|
||||
f = File.open("foo")
|
||||
|
||||
assert_raises(IOError) do
|
||||
f << "bar"
|
||||
end
|
||||
end
|
||||
|
||||
def test_file_opens_in_invalid_mode
|
||||
FileUtils.touch("foo")
|
||||
|
||||
assert_raises(ArgumentError) do
|
||||
File.open("foo", "an_illegal_mode")
|
||||
end
|
||||
end
|
||||
|
||||
def test_raises_error_when_cannot_find_file_in_read_mode
|
||||
assert_raises(Errno::ENOENT) do
|
||||
File.open("does_not_exist", "r")
|
||||
end
|
||||
end
|
||||
|
||||
def test_raises_error_when_cannot_find_file_in_read_write_mode
|
||||
assert_raises(Errno::ENOENT) do
|
||||
File.open("does_not_exist", "r+")
|
||||
end
|
||||
end
|
||||
|
||||
def test_creates_files_in_write_only_mode
|
||||
File.open("foo", "w")
|
||||
assert File.exists?("foo")
|
||||
end
|
||||
|
||||
def test_creates_files_in_read_write_truncate_mode
|
||||
File.open("foo", "w+")
|
||||
assert File.exists?("foo")
|
||||
end
|
||||
|
||||
def test_creates_files_in_append_write_only
|
||||
File.open("foo", "a")
|
||||
assert File.exists?("foo")
|
||||
end
|
||||
|
||||
def test_creates_files_in_append_read_write
|
||||
File.open("foo", "a+")
|
||||
assert File.exists?("foo")
|
||||
end
|
||||
|
||||
def test_file_in_write_only_raises_error_when_reading
|
||||
FileUtils.touch("foo")
|
||||
|
||||
f = File.open("foo", "w")
|
||||
|
||||
assert_raises(IOError) do
|
||||
f.read
|
||||
end
|
||||
end
|
||||
|
||||
def test_file_in_write_mode_truncates_existing_file
|
||||
File.open("foo", "w") { |f| f << "contents" }
|
||||
|
||||
f = File.open("foo", "w")
|
||||
|
||||
assert_equal "", File.read("foo")
|
||||
end
|
||||
|
||||
def test_file_in_read_write_truncation_mode_truncates_file
|
||||
File.open("foo", "w") { |f| f << "foo" }
|
||||
|
||||
f = File.open("foo", "w+")
|
||||
|
||||
assert_equal "", File.read("foo")
|
||||
end
|
||||
|
||||
def test_file_in_append_write_only_raises_error_when_reading
|
||||
FileUtils.touch("foo")
|
||||
|
||||
f = File.open("foo", "a")
|
||||
|
||||
assert_raises(IOError) do
|
||||
f.read
|
||||
end
|
||||
end
|
||||
|
||||
def test_can_read_files_once_written
|
||||
path = '/path/to/file.txt'
|
||||
File.open(path, 'w') do |f|
|
||||
@ -532,6 +618,14 @@ class FakeFSTest < Test::Unit::TestCase
|
||||
assert_equal 'works', File.open('new/nother') { |f| f.read }
|
||||
end
|
||||
|
||||
def test_can_symlink_through_file
|
||||
FileUtils.touch("/foo")
|
||||
|
||||
File.symlink("/foo", "/bar")
|
||||
|
||||
assert File.symlink?("/bar")
|
||||
end
|
||||
|
||||
def test_files_can_be_touched
|
||||
FileUtils.touch('touched_file')
|
||||
assert File.exists?('touched_file')
|
||||
@ -828,6 +922,144 @@ class FakeFSTest < Test::Unit::TestCase
|
||||
assert Dir.tmpdir == "/tmp"
|
||||
end
|
||||
|
||||
def test_hard_link_creates_file
|
||||
FileUtils.touch("/foo")
|
||||
|
||||
File.link("/foo", "/bar")
|
||||
assert File.exists?("/bar")
|
||||
end
|
||||
|
||||
def test_hard_link_with_missing_file_raises_error
|
||||
assert_raises(Errno::ENOENT) do
|
||||
File.link("/foo", "/bar")
|
||||
end
|
||||
end
|
||||
|
||||
def test_hard_link_with_existing_destination_file
|
||||
FileUtils.touch("/foo")
|
||||
FileUtils.touch("/bar")
|
||||
|
||||
assert_raises(Errno::EEXIST) do
|
||||
File.link("/foo", "/bar")
|
||||
end
|
||||
end
|
||||
|
||||
def test_hard_link_returns_0_when_successful
|
||||
FileUtils.touch("/foo")
|
||||
|
||||
assert_equal 0, File.link("/foo", "/bar")
|
||||
end
|
||||
|
||||
def test_hard_link_returns_duplicate_file
|
||||
File.open("/foo", "w") { |x| x << "some content" }
|
||||
|
||||
File.link("/foo", "/bar")
|
||||
assert_equal "some content", File.read("/bar")
|
||||
end
|
||||
|
||||
def test_hard_link_with_directory_raises_error
|
||||
Dir.mkdir "/foo"
|
||||
|
||||
assert_raises(Errno::EPERM) do
|
||||
File.link("/foo", "/bar")
|
||||
end
|
||||
end
|
||||
|
||||
def test_file_stat_returns_file_stat_object
|
||||
FileUtils.touch("/foo")
|
||||
assert_equal File::Stat, File.stat("/foo").class
|
||||
end
|
||||
|
||||
def test_can_delete_file_with_delete
|
||||
FileUtils.touch("/foo")
|
||||
|
||||
File.delete("/foo")
|
||||
|
||||
assert !File.exists?("/foo")
|
||||
end
|
||||
|
||||
def test_can_delete_multiple_files_with_delete
|
||||
FileUtils.touch("/foo")
|
||||
FileUtils.touch("/bar")
|
||||
|
||||
File.delete("/foo", "/bar")
|
||||
|
||||
assert !File.exists?("/foo")
|
||||
assert !File.exists?("/bar")
|
||||
end
|
||||
|
||||
def test_delete_raises_argument_error_with_no_filename_given
|
||||
assert_raises ArgumentError do
|
||||
File.delete
|
||||
end
|
||||
end
|
||||
|
||||
def test_delete_returns_number_one_when_given_one_arg
|
||||
FileUtils.touch("/foo")
|
||||
|
||||
assert_equal 1, File.delete("/foo")
|
||||
end
|
||||
|
||||
def test_delete_returns_number_two_when_given_two_args
|
||||
FileUtils.touch("/foo")
|
||||
FileUtils.touch("/bar")
|
||||
|
||||
assert_equal 2, File.delete("/foo", "/bar")
|
||||
end
|
||||
|
||||
def test_delete_raises_error_when_first_file_does_not_exist
|
||||
assert_raises Errno::ENOENT do
|
||||
File.delete("/foo")
|
||||
end
|
||||
end
|
||||
|
||||
def test_delete_does_not_raise_error_when_second_file_does_not_exist
|
||||
FileUtils.touch("/foo")
|
||||
|
||||
assert_nothing_raised do
|
||||
File.delete("/foo", "/bar")
|
||||
end
|
||||
end
|
||||
|
||||
def test_unlink_is_alias_for_delete
|
||||
assert_equal File.method(:unlink), File.method(:delete)
|
||||
end
|
||||
|
||||
def test_unlink_removes_only_one_file_content
|
||||
File.open("/foo", "w") { |f| f << "some_content" }
|
||||
File.link("/foo", "/bar")
|
||||
|
||||
File.unlink("/bar")
|
||||
File.read("/foo") == "some_content"
|
||||
end
|
||||
|
||||
def test_link_reports_correct_stat_info_after_unlinking
|
||||
File.open("/foo", "w") { |f| f << "some_content" }
|
||||
File.link("/foo", "/bar")
|
||||
|
||||
File.unlink("/bar")
|
||||
assert_equal 1, File.stat("/foo").nlink
|
||||
end
|
||||
|
||||
def test_delete_works_with_symlink
|
||||
FileUtils.touch("/foo")
|
||||
File.symlink("/foo", "/bar")
|
||||
|
||||
File.unlink("/bar")
|
||||
|
||||
assert File.exists?("/foo")
|
||||
assert !File.exists?("/bar")
|
||||
end
|
||||
|
||||
def test_delete_works_with_symlink_source
|
||||
FileUtils.touch("/foo")
|
||||
File.symlink("/foo", "/bar")
|
||||
|
||||
File.unlink("/foo")
|
||||
|
||||
assert !File.exists?("/foo")
|
||||
end
|
||||
|
||||
def here(fname)
|
||||
RealFile.expand_path(RealFile.dirname(__FILE__)+'/'+fname)
|
||||
end
|
||||
|
70
test/file/stat_test.rb
Normal file
70
test/file/stat_test.rb
Normal file
@ -0,0 +1,70 @@
|
||||
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
||||
require 'fakefs/safe'
|
||||
require 'test/unit'
|
||||
|
||||
class FileStatTest < Test::Unit::TestCase
|
||||
include FakeFS
|
||||
|
||||
def setup
|
||||
FileSystem.clear
|
||||
end
|
||||
|
||||
def touch(*args)
|
||||
FileUtils.touch(*args)
|
||||
end
|
||||
|
||||
def ln_s(*args)
|
||||
FileUtils.ln_s(*args)
|
||||
end
|
||||
|
||||
def mkdir(*args)
|
||||
Dir.mkdir(*args)
|
||||
end
|
||||
|
||||
def ln(*args)
|
||||
File.link(*args)
|
||||
end
|
||||
|
||||
def test_file_stat_init_with_non_existant_file
|
||||
assert_raises(Errno::ENOENT) do
|
||||
File::Stat.new("/foo")
|
||||
end
|
||||
end
|
||||
|
||||
def test_symlink_should_be_true_when_symlink
|
||||
touch("/foo")
|
||||
ln_s("/foo", "/bar")
|
||||
|
||||
assert File::Stat.new("/bar").symlink?
|
||||
end
|
||||
|
||||
def test_symlink_should_be_false_when_not_a_symlink
|
||||
FileUtils.touch("/foo")
|
||||
|
||||
assert !File::Stat.new("/foo").symlink?
|
||||
end
|
||||
|
||||
def test_should_return_false_for_directory_when_not_a_directory
|
||||
FileUtils.touch("/foo")
|
||||
|
||||
assert !File::Stat.new("/foo").directory?
|
||||
end
|
||||
|
||||
def test_should_return_true_for_directory_when_a_directory
|
||||
mkdir "/foo"
|
||||
|
||||
assert File::Stat.new("/foo").directory?
|
||||
end
|
||||
|
||||
def test_one_file_has_hard_link
|
||||
touch "testfile"
|
||||
assert_equal 1, File.stat("testfile").nlink
|
||||
end
|
||||
|
||||
def test_two_hard_links_show_nlinks_as_two
|
||||
touch "testfile"
|
||||
ln "testfile", "testfile.bak"
|
||||
|
||||
assert_equal 2, File.stat("testfile").nlink
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user