Add hard links. Closes #11

This commit is contained in:
Scott Taylor 2009-10-01 01:39:07 -04:00
parent 7e927d8ff0
commit bdcdc26d49
5 changed files with 168 additions and 6 deletions

View File

@ -1,16 +1,50 @@
module FakeFS module FakeFS
class FakeFile 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
end
def initialize(name = nil, parent = nil) def initialize(name = nil, parent = nil)
@name = name @name = name
@parent = parent @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 end
def clone(parent = nil) def clone(parent = nil)
clone = super() clone = super()
clone.parent = parent if parent clone.parent = parent if parent
clone.inode = inode.clone
clone clone
end end

View File

@ -116,10 +116,22 @@ module FakeFS
end end
def self.link(source, dest) def self.link(source, dest)
raise(Errno::ENOENT, "No such file or directory - #{source} or #{dest}") if !File.exists?(source) if directory?(source)
raise(Errno::EEXIST, "File exists - #{source} or #{dest}") if File.exists?(dest) 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
FileUtils.cp(source, dest) 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 0
end end
@ -147,6 +159,10 @@ module FakeFS
def directory? def directory?
File.directory?(@file) File.directory?(@file)
end end
def nlink
FileSystem.find(@file).links.size
end
end end
attr_reader :path attr_reader :path

88
test/fake/file_test.rb Normal file
View 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

View File

@ -957,6 +957,14 @@ class FakeFSTest < Test::Unit::TestCase
assert_equal "some content", File.read("/bar") assert_equal "some content", File.read("/bar")
end 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 def test_file_stat_returns_file_stat_object
FileUtils.touch("/foo") FileUtils.touch("/foo")
assert_equal File::Stat, File.stat("/foo").class assert_equal File::Stat, File.stat("/foo").class

View File

@ -21,6 +21,10 @@ class FileStatTest < Test::Unit::TestCase
Dir.mkdir(*args) Dir.mkdir(*args)
end end
def ln(*args)
File.link(*args)
end
def test_file_stat_init_with_non_existant_file def test_file_stat_init_with_non_existant_file
assert_raises(Errno::ENOENT) do assert_raises(Errno::ENOENT) do
File::Stat.new("/foo") File::Stat.new("/foo")
@ -51,4 +55,16 @@ class FileStatTest < Test::Unit::TestCase
assert File::Stat.new("/foo").directory? assert File::Stat.new("/foo").directory?
end 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 end