Add hard links. Closes #11
This commit is contained in:
parent
7e927d8ff0
commit
bdcdc26d49
@ -1,16 +1,50 @@
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -116,10 +116,22 @@ module FakeFS
|
||||
end
|
||||
|
||||
def self.link(source, dest)
|
||||
raise(Errno::ENOENT, "No such file or directory - #{source} or #{dest}") if !File.exists?(source)
|
||||
raise(Errno::EEXIST, "File exists - #{source} or #{dest}") if File.exists?(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
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
@ -147,6 +159,10 @@ module FakeFS
|
||||
def directory?
|
||||
File.directory?(@file)
|
||||
end
|
||||
|
||||
def nlink
|
||||
FileSystem.find(@file).links.size
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :path
|
||||
|
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
|
@ -957,6 +957,14 @@ class FakeFSTest < Test::Unit::TestCase
|
||||
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
|
||||
|
@ -21,6 +21,10 @@ class FileStatTest < Test::Unit::TestCase
|
||||
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")
|
||||
@ -51,4 +55,16 @@ class FileStatTest < Test::Unit::TestCase
|
||||
|
||||
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