fakefs 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/CONTRIBUTORS +12 -0
- data/README.markdown +40 -7
- data/Rakefile +27 -20
- data/lib/fakefs/base.rb +2 -1
- data/lib/fakefs/dir.rb +93 -2
- data/lib/fakefs/fake/dir.rb +8 -0
- data/lib/fakefs/fake/file.rb +53 -3
- data/lib/fakefs/fake/symlink.rb +8 -2
- data/lib/fakefs/file.rb +175 -17
- data/lib/fakefs/file_system.rb +25 -7
- data/lib/fakefs/fileutils.rb +23 -2
- data/lib/fakefs/spec_helpers.rb +46 -0
- data/lib/fakefs/version.rb +1 -1
- data/spec/fakefs/spec_helpers_spec.rb +57 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +3 -0
- data/test/fake/file_test.rb +88 -0
- data/test/fake/symlink_test.rb +12 -0
- data/test/fakefs_test.rb +766 -53
- data/test/file/stat_test.rb +70 -0
- data/test/safe_test.rb +22 -0
- metadata +17 -3
data/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*.sw?
|
data/CONTRIBUTORS
ADDED
data/README.markdown
CHANGED
|
@@ -4,7 +4,7 @@ FakeFS
|
|
|
4
4
|
Mocha is great. But when your library is all about manipulating the
|
|
5
5
|
filesystem, you really want to test the behavior and not the implementation.
|
|
6
6
|
|
|
7
|
-
If you're mocking and stubbing every call to FileUtils or File, you're
|
|
7
|
+
If you're mocking and stubbing every call to FileUtils or File, you're
|
|
8
8
|
tightly coupling your tests with the implementation.
|
|
9
9
|
|
|
10
10
|
def test_creates_directory
|
|
@@ -48,21 +48,54 @@ Don't Fake the FS Immediately
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
RSpec
|
|
52
|
+
-----------------------------
|
|
53
|
+
The above approach works with RSpec as well. In addition to this you may use the
|
|
54
|
+
'use_fakefs' macro to turn FakeFS on and off in a given example group. See
|
|
55
|
+
lib/spec_helpers for more details on it's usage.
|
|
56
|
+
|
|
57
|
+
|
|
51
58
|
How is this different than MockFS?
|
|
52
59
|
----------------------------------
|
|
53
60
|
|
|
54
|
-
FakeFS provides a test suite and works with symlinks. It's also strictly a
|
|
61
|
+
FakeFS provides a test suite and works with symlinks. It's also strictly a
|
|
55
62
|
test-time dependency: your actual library does not need to use or know about
|
|
56
63
|
FakeFS.
|
|
57
64
|
|
|
58
65
|
|
|
66
|
+
Caveats
|
|
67
|
+
-------
|
|
68
|
+
|
|
69
|
+
FakeFS internally uses the `Pathname` and `FileUtils` constants. If you use
|
|
70
|
+
these in your app, be certain you're properly requiring them and not counting
|
|
71
|
+
on FakeFS' own require.
|
|
72
|
+
|
|
73
|
+
|
|
59
74
|
Speed?
|
|
60
75
|
------
|
|
61
|
-
http://gist.github.com/156091
|
|
76
|
+
<http://gist.github.com/156091>
|
|
62
77
|
|
|
63
78
|
|
|
64
|
-
|
|
65
|
-
|
|
79
|
+
Installation
|
|
80
|
+
------------
|
|
81
|
+
|
|
82
|
+
### [Gemcutter](http://gemcutter.org/)
|
|
83
|
+
|
|
84
|
+
$ gem install fakefs
|
|
85
|
+
|
|
86
|
+
### [Rip](http://hellorip.com)
|
|
87
|
+
|
|
88
|
+
$ rip install git://github.com/defunkt/fakefs.git
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
Meta
|
|
92
|
+
----
|
|
66
93
|
|
|
67
|
-
*
|
|
68
|
-
*
|
|
94
|
+
* Code: `git clone git://github.com/defunkt/fakefs.git`
|
|
95
|
+
* Home: <http://github.com/defunkt/fakefs>
|
|
96
|
+
* Docs: <http://defunkt.github.com/fakefs>
|
|
97
|
+
* Bugs: <http://github.com/defunkt/fakefs/issues>
|
|
98
|
+
* List: <http://groups.google.com/group/fakefs>
|
|
99
|
+
* Test: <http://runcoderun.com/defunkt/fakefs>
|
|
100
|
+
* Gems: <http://gemcutter.org/gems/fakefs>
|
|
101
|
+
* Boss: Chris Wanstrath :: <http://github.com/defunkt>
|
data/Rakefile
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
desc "Run tests"
|
|
2
|
+
task :test do
|
|
3
|
+
Dir['test/**/*_test.rb'].each { |file| require file }
|
|
3
4
|
end
|
|
4
5
|
|
|
6
|
+
task :default => :test
|
|
7
|
+
|
|
5
8
|
begin
|
|
6
9
|
require 'jeweler'
|
|
7
10
|
|
|
8
|
-
# We're not putting VERSION or VERSION.yml in the root,
|
|
9
|
-
# so we have to help Jeweler find our version.
|
|
10
11
|
$LOAD_PATH.unshift File.dirname(__FILE__) + '/lib'
|
|
11
12
|
require 'fakefs/version'
|
|
12
13
|
|
|
13
|
-
FakeFS::Version.instance_eval do
|
|
14
|
-
def refresh
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class Jeweler
|
|
19
|
-
def version_helper
|
|
20
|
-
FakeFS::Version
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def version_exists?
|
|
24
|
-
true
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
14
|
Jeweler::Tasks.new do |gemspec|
|
|
29
15
|
gemspec.name = "fakefs"
|
|
30
16
|
gemspec.summary = "A fake filesystem. Use it in your tests."
|
|
@@ -33,8 +19,29 @@ begin
|
|
|
33
19
|
gemspec.description = "A fake filesystem. Use it in your tests."
|
|
34
20
|
gemspec.authors = ["Chris Wanstrath"]
|
|
35
21
|
gemspec.has_rdoc = false
|
|
22
|
+
gemspec.version = FakeFS::Version.to_s
|
|
36
23
|
end
|
|
37
24
|
rescue LoadError
|
|
38
25
|
puts "Jeweler not available."
|
|
39
|
-
puts "Install it with: gem install
|
|
26
|
+
puts "Install it with: gem install jeweler"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
begin
|
|
30
|
+
require 'sdoc_helpers'
|
|
31
|
+
rescue LoadError
|
|
32
|
+
puts "sdoc support not enabled. Please gem install sdoc-helpers."
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc "Build a gem"
|
|
36
|
+
task :gem => [ :gemspec, :build ]
|
|
37
|
+
|
|
38
|
+
desc "Push a new version to Gemcutter"
|
|
39
|
+
task :publish => [ :gemspec, :build ] do
|
|
40
|
+
abort("Tests failed!") unless system("rake test")
|
|
41
|
+
system "git tag v#{FakeFS::Version}"
|
|
42
|
+
system "git push origin v#{FakeFS::Version}"
|
|
43
|
+
system "git push origin master"
|
|
44
|
+
system "gem push pkg/fakefs-#{FakeFS::Version}.gem"
|
|
45
|
+
system "git clean -fd"
|
|
46
|
+
exec "rake pages"
|
|
40
47
|
end
|
data/lib/fakefs/base.rb
CHANGED
data/lib/fakefs/dir.rb
CHANGED
|
@@ -1,7 +1,55 @@
|
|
|
1
1
|
module FakeFS
|
|
2
2
|
class Dir
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
include Enumerable
|
|
4
|
+
|
|
5
|
+
def initialize(string)
|
|
6
|
+
raise Errno::ENOENT, string unless FileSystem.find(string)
|
|
7
|
+
@path = string
|
|
8
|
+
@open = true
|
|
9
|
+
@pointer = 0
|
|
10
|
+
@contents = [ '.', '..', ] + FileSystem.find(@path).values
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def close
|
|
14
|
+
@open = false
|
|
15
|
+
@pointer = nil
|
|
16
|
+
@contents = nil
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def each(&block)
|
|
21
|
+
while f = read
|
|
22
|
+
yield f
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def path
|
|
27
|
+
@path
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def pos
|
|
31
|
+
@pointer
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def pos=(integer)
|
|
35
|
+
@pointer = integer
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def read
|
|
39
|
+
raise IOError, "closed directory" if @pointer == nil
|
|
40
|
+
n = @contents[@pointer]
|
|
41
|
+
@pointer += 1
|
|
42
|
+
n.to_s.gsub(path + '/', '') if n
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def rewind
|
|
46
|
+
@pointer = 0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def seek(integer)
|
|
50
|
+
raise IOError, "closed directory" if @pointer == nil
|
|
51
|
+
@pointer = integer
|
|
52
|
+
@contents[integer]
|
|
5
53
|
end
|
|
6
54
|
|
|
7
55
|
def self.[](pattern)
|
|
@@ -12,12 +60,55 @@ module FakeFS
|
|
|
12
60
|
FileSystem.chdir(dir, &blk)
|
|
13
61
|
end
|
|
14
62
|
|
|
63
|
+
def self.chroot(string)
|
|
64
|
+
# Not implemented yet
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.delete(string)
|
|
68
|
+
raise SystemCallError, "No such file or directory - #{string}" unless FileSystem.find(string).values.empty?
|
|
69
|
+
FileSystem.delete(string)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.entries(dirname)
|
|
73
|
+
raise SystemCallError, dirname unless FileSystem.find(dirname)
|
|
74
|
+
Dir.new(dirname).map { |file| File.basename(file) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.foreach(dirname, &block)
|
|
78
|
+
Dir.open(dirname) { |file| yield file }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.glob(pattern)
|
|
82
|
+
[FileSystem.find(pattern) || []].flatten.map{|e| e.to_s}.sort
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.mkdir(string, integer = 0)
|
|
86
|
+
parent = string.split('/')
|
|
87
|
+
parent.pop
|
|
88
|
+
raise Errno::ENOENT, "No such file or directory - #{string}" unless parent.join == "" || FileSystem.find(parent.join('/'))
|
|
89
|
+
FileUtils.mkdir_p(string)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def self.open(string, &block)
|
|
93
|
+
if block_given?
|
|
94
|
+
Dir.new(string).each { |file| yield(file) }
|
|
95
|
+
else
|
|
96
|
+
Dir.new(string)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def self.tmpdir
|
|
101
|
+
'/tmp'
|
|
102
|
+
end
|
|
103
|
+
|
|
15
104
|
def self.pwd
|
|
16
105
|
FileSystem.current_dir.to_s
|
|
17
106
|
end
|
|
18
107
|
|
|
19
108
|
class << self
|
|
20
109
|
alias_method :getwd, :pwd
|
|
110
|
+
alias_method :rmdir, :delete
|
|
111
|
+
alias_method :unlink, :delete
|
|
21
112
|
end
|
|
22
113
|
end
|
|
23
114
|
end
|
data/lib/fakefs/fake/dir.rb
CHANGED
data/lib/fakefs/fake/file.rb
CHANGED
|
@@ -1,16 +1,61 @@
|
|
|
1
1
|
module FakeFS
|
|
2
2
|
class FakeFile
|
|
3
|
-
attr_accessor :name, :parent, :content
|
|
3
|
+
attr_accessor :name, :parent, :content, :mtime
|
|
4
|
+
|
|
5
|
+
class Inode
|
|
6
|
+
def initialize(file_owner)
|
|
7
|
+
@content = ""
|
|
8
|
+
@links = [file_owner]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
attr_accessor :content
|
|
12
|
+
attr_accessor :links
|
|
13
|
+
|
|
14
|
+
def link(file)
|
|
15
|
+
links << file unless links.include?(file)
|
|
16
|
+
file.inode = self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def unlink(file)
|
|
20
|
+
links.delete(file)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def clone
|
|
24
|
+
clone = super
|
|
25
|
+
clone.content = content.dup
|
|
26
|
+
clone
|
|
27
|
+
end
|
|
28
|
+
end
|
|
4
29
|
|
|
5
30
|
def initialize(name = nil, parent = nil)
|
|
6
|
-
@name
|
|
31
|
+
@name = name
|
|
7
32
|
@parent = parent
|
|
8
|
-
@
|
|
33
|
+
@inode = Inode.new(self)
|
|
34
|
+
@mtime = Time.now
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
attr_accessor :inode
|
|
38
|
+
|
|
39
|
+
def content
|
|
40
|
+
@inode.content
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def content=(str)
|
|
44
|
+
@inode.content = str
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def links
|
|
48
|
+
@inode.links
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def link(other_file)
|
|
52
|
+
@inode.link(other_file)
|
|
9
53
|
end
|
|
10
54
|
|
|
11
55
|
def clone(parent = nil)
|
|
12
56
|
clone = super()
|
|
13
57
|
clone.parent = parent if parent
|
|
58
|
+
clone.inode = inode.clone
|
|
14
59
|
clone
|
|
15
60
|
end
|
|
16
61
|
|
|
@@ -25,5 +70,10 @@ module FakeFS
|
|
|
25
70
|
def to_s
|
|
26
71
|
File.join(parent.to_s, name)
|
|
27
72
|
end
|
|
73
|
+
|
|
74
|
+
def delete
|
|
75
|
+
inode.unlink(self)
|
|
76
|
+
parent.delete(self)
|
|
77
|
+
end
|
|
28
78
|
end
|
|
29
79
|
end
|
data/lib/fakefs/fake/symlink.rb
CHANGED
|
@@ -15,12 +15,18 @@ module FakeFS
|
|
|
15
15
|
FileSystem.find(target)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def
|
|
19
|
-
|
|
18
|
+
def delete
|
|
19
|
+
parent.delete(self)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def respond_to?(method)
|
|
23
23
|
entry.respond_to?(method)
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def method_missing(*args, &block)
|
|
29
|
+
entry.send(*args, &block)
|
|
30
|
+
end
|
|
25
31
|
end
|
|
26
32
|
end
|
data/lib/fakefs/file.rb
CHANGED
|
@@ -2,6 +2,34 @@ module FakeFS
|
|
|
2
2
|
class File
|
|
3
3
|
PATH_SEPARATOR = '/'
|
|
4
4
|
|
|
5
|
+
MODES = [
|
|
6
|
+
READ_ONLY = "r",
|
|
7
|
+
READ_WRITE = "r+",
|
|
8
|
+
WRITE_ONLY = "w",
|
|
9
|
+
READ_WRITE_TRUNCATE = "w+",
|
|
10
|
+
APPEND_WRITE_ONLY = "a",
|
|
11
|
+
APPEND_READ_WRITE = "a+"
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
FILE_CREATION_MODES = MODES - [READ_ONLY, READ_WRITE]
|
|
15
|
+
|
|
16
|
+
MODE_BITMASK = RealFile::RDONLY |
|
|
17
|
+
RealFile::WRONLY |
|
|
18
|
+
RealFile::RDWR |
|
|
19
|
+
RealFile::APPEND |
|
|
20
|
+
RealFile::CREAT |
|
|
21
|
+
RealFile::EXCL |
|
|
22
|
+
RealFile::NONBLOCK |
|
|
23
|
+
RealFile::TRUNC |
|
|
24
|
+
RealFile::NOCTTY |
|
|
25
|
+
RealFile::SYNC
|
|
26
|
+
|
|
27
|
+
FILE_CREATION_BITMASK = RealFile::CREAT
|
|
28
|
+
|
|
29
|
+
def self.extname(path)
|
|
30
|
+
RealFile.extname(path)
|
|
31
|
+
end
|
|
32
|
+
|
|
5
33
|
def self.join(*parts)
|
|
6
34
|
parts * PATH_SEPARATOR
|
|
7
35
|
end
|
|
@@ -12,6 +40,30 @@ module FakeFS
|
|
|
12
40
|
|
|
13
41
|
class << self
|
|
14
42
|
alias_method :exists?, :exist?
|
|
43
|
+
|
|
44
|
+
# Assuming that everyone can read and write files
|
|
45
|
+
alias_method :readable?, :exist?
|
|
46
|
+
alias_method :writable?, :exist?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.mtime(path)
|
|
50
|
+
if exists?(path)
|
|
51
|
+
FileSystem.find(path).mtime
|
|
52
|
+
else
|
|
53
|
+
raise Errno::ENOENT
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.size(path)
|
|
58
|
+
read(path).length
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.size?(path)
|
|
62
|
+
if exists?(path) && !size(path).zero?
|
|
63
|
+
true
|
|
64
|
+
else
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
15
67
|
end
|
|
16
68
|
|
|
17
69
|
def self.const_missing(name)
|
|
@@ -61,11 +113,11 @@ module FakeFS
|
|
|
61
113
|
FileSystem.find(symlink.target).to_s
|
|
62
114
|
end
|
|
63
115
|
|
|
64
|
-
def self.open(path, mode=
|
|
116
|
+
def self.open(path, mode=READ_ONLY, perm = 0644)
|
|
65
117
|
if block_given?
|
|
66
|
-
yield new(path, mode)
|
|
118
|
+
yield new(path, mode, perm)
|
|
67
119
|
else
|
|
68
|
-
new(path, mode)
|
|
120
|
+
new(path, mode, perm)
|
|
69
121
|
end
|
|
70
122
|
end
|
|
71
123
|
|
|
@@ -82,43 +134,149 @@ module FakeFS
|
|
|
82
134
|
read(path).split("\n")
|
|
83
135
|
end
|
|
84
136
|
|
|
137
|
+
def self.link(source, dest)
|
|
138
|
+
if directory?(source)
|
|
139
|
+
raise Errno::EPERM, "Operation not permitted - #{source} or #{dest}"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
if !exists?(source)
|
|
143
|
+
raise Errno::ENOENT, "No such file or directory - #{source} or #{dest}"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
if exists?(dest)
|
|
147
|
+
raise Errno::EEXIST, "File exists - #{source} or #{dest}"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
source = FileSystem.find(source)
|
|
151
|
+
dest = FileSystem.add(dest, source.entry.clone)
|
|
152
|
+
source.link(dest)
|
|
153
|
+
|
|
154
|
+
0
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def self.delete(file_name, *additional_file_names)
|
|
158
|
+
if !exists?(file_name)
|
|
159
|
+
raise Errno::ENOENT, "No such file or directory - #{file_name}"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
FileUtils.rm(file_name)
|
|
163
|
+
|
|
164
|
+
additional_file_names.each do |file_name|
|
|
165
|
+
FileUtils.rm(file_name)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
additional_file_names.size + 1
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
class << self
|
|
172
|
+
alias_method :unlink, :delete
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def self.symlink(source, dest)
|
|
176
|
+
FileUtils.ln_s(source, dest)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def self.stat(file)
|
|
180
|
+
File::Stat.new(file)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
class Stat
|
|
184
|
+
def initialize(file)
|
|
185
|
+
if !File.exists?(file)
|
|
186
|
+
raise(Errno::ENOENT, "No such file or directory - #{file}")
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
@file = file
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def symlink?
|
|
193
|
+
File.symlink?(@file)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def directory?
|
|
197
|
+
File.directory?(@file)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def nlink
|
|
201
|
+
FileSystem.find(@file).links.size
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
85
205
|
attr_reader :path
|
|
86
|
-
|
|
206
|
+
|
|
207
|
+
def initialize(path, mode = READ_ONLY, perm = nil)
|
|
87
208
|
@path = path
|
|
88
209
|
@mode = mode
|
|
89
210
|
@file = FileSystem.find(path)
|
|
90
211
|
@open = true
|
|
212
|
+
|
|
213
|
+
check_modes!
|
|
214
|
+
|
|
215
|
+
file_creation_mode? ? create_missing_file : check_file_existence!
|
|
216
|
+
|
|
217
|
+
@stream = StringIO.new(@file.content, mode)
|
|
91
218
|
end
|
|
92
219
|
|
|
93
220
|
def close
|
|
94
221
|
@open = false
|
|
95
222
|
end
|
|
96
223
|
|
|
97
|
-
def read
|
|
98
|
-
|
|
99
|
-
|
|
224
|
+
def read(chunk = nil)
|
|
225
|
+
@stream.read(chunk)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def rewind
|
|
229
|
+
@stream.rewind
|
|
100
230
|
end
|
|
101
231
|
|
|
102
232
|
def exists?
|
|
103
|
-
|
|
233
|
+
true
|
|
104
234
|
end
|
|
105
235
|
|
|
106
|
-
def puts(content)
|
|
107
|
-
|
|
236
|
+
def puts(*content)
|
|
237
|
+
@stream.puts(*content)
|
|
108
238
|
end
|
|
109
239
|
|
|
110
240
|
def write(content)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if !File.exists?(@path)
|
|
114
|
-
@file = FileSystem.add(path, FakeFile.new)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
@file.content += content
|
|
241
|
+
@stream.write(content)
|
|
118
242
|
end
|
|
119
243
|
alias_method :print, :write
|
|
120
244
|
alias_method :<<, :write
|
|
121
245
|
|
|
122
246
|
def flush; self; end
|
|
247
|
+
|
|
248
|
+
def seek(amount, whence = SEEK_SET)
|
|
249
|
+
@stream.seek(amount, whence)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
private
|
|
253
|
+
|
|
254
|
+
def check_modes!
|
|
255
|
+
StringIO.new("", @mode)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def check_file_existence!
|
|
259
|
+
unless @file
|
|
260
|
+
raise Errno::ENOENT, "No such file or directory - #{@file}"
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def file_creation_mode?
|
|
265
|
+
mode_in?(FILE_CREATION_MODES) || mode_in_bitmask?(FILE_CREATION_BITMASK)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def mode_in?(list)
|
|
269
|
+
list.any? { |element| @mode.include?(element) } if @mode.respond_to?(:include?)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def mode_in_bitmask?(mask)
|
|
273
|
+
(@mode & mask) != 0 if @mode.is_a?(Integer)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def create_missing_file
|
|
277
|
+
if !File.exists?(@path)
|
|
278
|
+
@file = FileSystem.add(path, FakeFile.new)
|
|
279
|
+
end
|
|
280
|
+
end
|
|
123
281
|
end
|
|
124
282
|
end
|
data/lib/fakefs/file_system.rb
CHANGED
|
@@ -22,9 +22,9 @@ module FakeFS
|
|
|
22
22
|
def find(path)
|
|
23
23
|
parts = path_parts(normalize_path(path))
|
|
24
24
|
return fs if parts.empty? # '/'
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
entries = find_recurser(fs, parts).flatten
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
case entries.length
|
|
29
29
|
when 0 then nil
|
|
30
30
|
when 1 then entries.first
|
|
@@ -54,7 +54,7 @@ module FakeFS
|
|
|
54
54
|
files.each do |f|
|
|
55
55
|
if RealFile.file?(f)
|
|
56
56
|
FileUtils.mkdir_p(File.dirname(f))
|
|
57
|
-
File.open(f,
|
|
57
|
+
File.open(f, File::WRITE_ONLY) do |g|
|
|
58
58
|
g.print RealFile.open(f){|h| h.read }
|
|
59
59
|
end
|
|
60
60
|
elsif RealFile.directory?(f)
|
|
@@ -66,8 +66,8 @@ module FakeFS
|
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def delete(path)
|
|
69
|
-
if
|
|
70
|
-
|
|
69
|
+
if node = FileSystem.find(path)
|
|
70
|
+
node.delete
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
|
|
@@ -106,13 +106,31 @@ module FakeFS
|
|
|
106
106
|
return [] unless dir.respond_to? :[]
|
|
107
107
|
|
|
108
108
|
pattern , *parts = parts
|
|
109
|
-
matches =
|
|
109
|
+
matches = case pattern
|
|
110
|
+
when '**'
|
|
111
|
+
case parts
|
|
112
|
+
when ['*'], []
|
|
113
|
+
parts = [] # end recursion
|
|
114
|
+
directories_under(dir).map do |d|
|
|
115
|
+
d.values.select{|f| f.is_a? FakeFile }
|
|
116
|
+
end.flatten.uniq
|
|
117
|
+
else
|
|
118
|
+
directories_under(dir)
|
|
119
|
+
end
|
|
120
|
+
else
|
|
121
|
+
dir.reject {|k,v| /\A#{pattern.gsub('?','.').gsub('*', '.*')}\Z/ !~ k }.values
|
|
122
|
+
end
|
|
110
123
|
|
|
111
124
|
if parts.empty? # we're done recursing
|
|
112
125
|
matches
|
|
113
126
|
else
|
|
114
127
|
matches.map{|entry| find_recurser(entry, parts) }
|
|
115
128
|
end
|
|
116
|
-
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def directories_under(dir)
|
|
132
|
+
children = dir.values.select{|f| f.is_a? FakeDir}
|
|
133
|
+
([dir] + children + children.map{|c| directories_under(c)}).flatten.uniq
|
|
134
|
+
end
|
|
117
135
|
end
|
|
118
136
|
end
|