Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
460 lines (363 sloc) 9.66 KB
require 'stringio'
module FakeFS
class File < StringIO
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]
MODE_BITMASK = RealFile::RDONLY |
RealFile::WRONLY |
RealFile::RDWR |
RealFile::APPEND |
RealFile::CREAT |
RealFile::EXCL |
RealFile::NONBLOCK |
RealFile::TRUNC |
RealFile::NOCTTY |
RealFile::SYNC
FILE_CREATION_BITMASK = RealFile::CREAT
def self.extname(path)
RealFile.extname(path)
end
def self.join(*parts)
RealFile.join(parts)
end
def self.exist?(path)
if(File.symlink?(path)) then
referent = File.expand_path(File.readlink(path), File.dirname(path))
exist?(referent)
else
!!FileSystem.find(path)
end
end
class << self
alias_method :exists?, :exist?
# Assuming that everyone can read and write files
alias_method :readable?, :exist?
alias_method :writable?, :exist?
end
def self.mtime(path)
if exists?(path)
FileSystem.find(path).mtime
else
raise Errno::ENOENT
end
end
def self.ctime(path)
if exists?(path)
FileSystem.find(path).ctime
else
raise Errno::ENOENT
end
end
def self.atime(path)
if exists?(path)
FileSystem.find(path).atime
else
raise Errno::ENOENT
end
end
def self.utime(atime, mtime, *paths)
paths.each do |path|
if exists?(path)
FileSystem.find(path).atime = atime
FileSystem.find(path).mtime = mtime
else
raise Errno::ENOENT
end
end
paths.size
end
def self.size(path)
read(path).length
end
def self.size?(path)
if exists?(path) && !size(path).zero?
true
else
nil
end
end
def self.const_missing(name)
RealFile.const_get(name)
end
def self.directory?(path)
if path.respond_to? :entry
path.entry.is_a? FakeDir
else
result = FileSystem.find(path)
result ? result.entry.is_a?(FakeDir) : false
end
end
def self.symlink?(path)
if path.respond_to? :entry
path.is_a? FakeSymlink
else
FileSystem.find(path).is_a? FakeSymlink
end
end
def self.file?(path)
if path.respond_to? :entry
path.entry.is_a? FakeFile
else
result = FileSystem.find(path)
result ? result.entry.is_a?(FakeFile) : false
end
end
def self.expand_path(*args)
RealFile.expand_path(*args)
end
def self.basename(*args)
RealFile.basename(*args)
end
def self.dirname(path)
RealFile.dirname(path)
end
def self.readlink(path)
symlink = FileSystem.find(path)
symlink.target
end
def self.read(path)
file = new(path)
if file.exists?
FileSystem.find(path).atime = Time.now
file.read
else
raise Errno::ENOENT
end
end
def self.readlines(path)
read(path).split("\n")
end
def self.rename(source, dest)
if directory?(source) && file?(dest)
raise Errno::ENOTDIR, "Not a directory - #{source} or #{dest}"
elsif file?(source) && directory?(dest)
raise Errno::EISDIR, "Is a directory - #{source} or #{dest}"
end
if target = FileSystem.find(source)
FileSystem.add(dest, target.entry.clone)
FileSystem.delete(source)
else
raise Errno::ENOENT, "No such file or directory - #{source} or #{dest}"
end
0
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
def self.lstat(file)
File::Stat.new(file, true)
end
def self.split(path)
return RealFile.split(path)
end
def self.chmod(mode_int, filename)
FileSystem.find(filename).mode = 0100000 + mode_int
end
def self.chown(owner_int, group_int, filename)
file = FileSystem.find(filename)
owner_int.is_a?(Fixnum) or raise TypeError, "can't convert String into Integer"
group_int.is_a?(Fixnum) or raise TypeError, "can't convert String into Integer"
file.uid = owner_int
file.gid = group_int
end
def self.umask
RealFile.umask
end
class Stat
attr_reader :ctime, :mtime, :atime, :mode, :uid, :gid
def initialize(file, __lstat = false)
if !File.exists?(file)
raise(Errno::ENOENT, "No such file or directory - #{file}")
end
@file = file
@fake_file = FileSystem.find(@file)
@__lstat = __lstat
@ctime = @fake_file.ctime
@mtime = @fake_file.mtime
@atime = @fake_file.atime
@mode = @fake_file.mode
@uid = @fake_file.uid
@gid = @fake_file.gid
end
def symlink?
File.symlink?(@file)
end
def directory?
File.directory?(@file)
end
def nlink
@fake_file.links.size
end
def size
if @__lstat && symlink?
@fake_file.target.size
else
File.size(@file)
end
end
end
attr_reader :path
def initialize(path, mode = READ_ONLY, perm = nil)
@path = path
@mode = mode
@file = FileSystem.find(path)
@autoclose = true
check_modes!
file_creation_mode? ? create_missing_file : check_file_existence!
super(@file.content, mode)
end
def exists?
true
end
alias_method :tell=, :pos=
alias_method :sysread, :read
alias_method :syswrite, :write
undef_method :closed_read?
undef_method :closed_write?
undef_method :length
undef_method :size
undef_method :string
undef_method :string=
def ioctl(integer_cmd, arg)
raise NotImplementedError
end
def read_nonblock(maxlen, outbuf = nil)
raise NotImplementedError
end
def stat
self.class.stat(@path)
end
def lstat
self.class.lstat(@path)
end
def sysseek(position, whence = SEEK_SET)
seek(position, whence)
pos
end
alias_method :to_i, :fileno
def to_io
self
end
def write_nonblock(string)
raise NotImplementedError
end
def readpartial(maxlen, outbuf = nil)
raise NotImplementedError
end
def atime
self.class.atime(@path)
end
def ctime
self.class.ctime(@path)
end
def flock(locking_constant)
raise NotImplementedError
end
def mtime
self.class.mtime(@path)
end
def chmod(mode_int)
@file.mode = 0100000 + mode_int
end
def chown(owner_int, group_int)
owner_int.is_a?(Fixnum) or raise TypeError, "can't convert String into Integer"
group_int.is_a?(Fixnum) or raise TypeError, "can't convert String into Integer"
@file.uid = owner_int
@file.gid = group_int
end
if RUBY_VERSION >= "1.9"
def binmode?
raise NotImplementedError
end
def close_on_exec=(bool)
raise NotImplementedError
end
def close_on_exec?
raise NotImplementedError
end
def to_path
@path
end
end
if RUBY_VERSION >= "1.9.2"
attr_writer :autoclose
def autoclose?
@autoclose
end
alias_method :fdatasync, :flush
def size
File.size(@path)
end
end
private
def check_modes!
StringIO.new("", @mode)
end
def check_file_existence!
raise Errno::ENOENT, @path unless @file
end
def file_creation_mode?
mode_in?(FILE_CREATION_MODES) || mode_in_bitmask?(FILE_CREATION_BITMASK)
end
def mode_in?(list)
list.any? { |element| @mode.include?(element) } if @mode.respond_to?(:include?)
end
def mode_in_bitmask?(mask)
(@mode & mask) != 0 if @mode.is_a?(Integer)
end
# Create a missing file if the path is valid.
#
def create_missing_file
raise Errno::EISDIR, "Is a directory - #{path}" if File.directory?(@path)
if !File.exists?(@path) # Unnecessary check, probably.
dirname = RealFile.dirname @path
unless dirname == "."
dir = FileSystem.find dirname
unless dir.kind_of? FakeDir
raise Errno::ENOENT, "No such file or directory - #{path}"
end
end
@file = FileSystem.add(path, FakeFile.new)
end
end
end
end
Jump to Line
Something went wrong with that request. Please try again.