mnoble-fakefs 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ module FakeFS
2
+ class FakeDir < Hash
3
+ attr_accessor :name, :parent
4
+ attr_reader :ctime, :mtime
5
+
6
+ def initialize(name = nil, parent = nil)
7
+ @name = name
8
+ @parent = parent
9
+ @ctime = Time.now
10
+ @mtime = @ctime
11
+ end
12
+
13
+ def entry
14
+ self
15
+ end
16
+
17
+ def inspect
18
+ "(FakeDir name:#{name.inspect} parent:#{parent.to_s.inspect} size:#{size})"
19
+ end
20
+
21
+ def clone(parent = nil)
22
+ clone = Marshal.load(Marshal.dump(self))
23
+ clone.each do |key, value|
24
+ value.parent = clone
25
+ end
26
+ clone.parent = parent if parent
27
+ clone
28
+ end
29
+
30
+ def to_s
31
+ if parent && parent.to_s != '.'
32
+ File.join(parent.to_s, name)
33
+ elsif parent && parent.to_s == '.'
34
+ "#{File::PATH_SEPARATOR}#{name}"
35
+ else
36
+ name
37
+ end
38
+ end
39
+
40
+ def delete(node = self)
41
+ if node == self
42
+ parent.delete(self)
43
+ else
44
+ super(node.name)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,81 @@
1
+ module FakeFS
2
+ class FakeFile
3
+ attr_accessor :name, :parent, :content, :mtime
4
+ attr_reader :ctime
5
+
6
+ class Inode
7
+ def initialize(file_owner)
8
+ @content = ""
9
+ @links = [file_owner]
10
+ end
11
+
12
+ attr_accessor :content
13
+ attr_accessor :links
14
+
15
+ def link(file)
16
+ links << file unless links.include?(file)
17
+ file.inode = self
18
+ end
19
+
20
+ def unlink(file)
21
+ links.delete(file)
22
+ end
23
+
24
+ def clone
25
+ clone = super
26
+ clone.content = content.dup
27
+ clone
28
+ end
29
+ end
30
+
31
+ def initialize(name = nil, parent = nil)
32
+ @name = name
33
+ @parent = parent
34
+ @inode = Inode.new(self)
35
+ @ctime = Time.now
36
+ @mtime = @ctime
37
+ end
38
+
39
+ attr_accessor :inode
40
+
41
+ def content
42
+ @inode.content
43
+ end
44
+
45
+ def content=(str)
46
+ @inode.content = str
47
+ end
48
+
49
+ def links
50
+ @inode.links
51
+ end
52
+
53
+ def link(other_file)
54
+ @inode.link(other_file)
55
+ end
56
+
57
+ def clone(parent = nil)
58
+ clone = super()
59
+ clone.parent = parent if parent
60
+ clone.inode = inode.clone
61
+ clone
62
+ end
63
+
64
+ def entry
65
+ self
66
+ end
67
+
68
+ def inspect
69
+ "(FakeFile name:#{name.inspect} parent:#{parent.to_s.inspect} size:#{content.size})"
70
+ end
71
+
72
+ def to_s
73
+ File.join(parent.to_s, name)
74
+ end
75
+
76
+ def delete
77
+ inode.unlink(self)
78
+ parent.delete(self)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,32 @@
1
+ module FakeFS
2
+ class FakeSymlink
3
+ attr_accessor :name, :target
4
+ alias_method :to_s, :name
5
+
6
+ def initialize(target)
7
+ @target = target
8
+ end
9
+
10
+ def inspect
11
+ "symlink(#{target.split('/').last})"
12
+ end
13
+
14
+ def entry
15
+ FileSystem.find(target)
16
+ end
17
+
18
+ def delete
19
+ parent.delete(self)
20
+ end
21
+
22
+ def respond_to?(method)
23
+ entry.respond_to?(method)
24
+ end
25
+
26
+ private
27
+
28
+ def method_missing(*args, &block)
29
+ entry.send(*args, &block)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,403 @@
1
+ require 'stringio'
2
+
3
+ module FakeFS
4
+ class File < StringIO
5
+ PATH_SEPARATOR = '/'
6
+
7
+ MODES = [
8
+ READ_ONLY = "r",
9
+ READ_WRITE = "r+",
10
+ WRITE_ONLY = "w",
11
+ READ_WRITE_TRUNCATE = "w+",
12
+ APPEND_WRITE_ONLY = "a",
13
+ APPEND_READ_WRITE = "a+"
14
+ ]
15
+
16
+ FILE_CREATION_MODES = MODES - [READ_ONLY, READ_WRITE]
17
+
18
+ MODE_BITMASK = RealFile::RDONLY |
19
+ RealFile::WRONLY |
20
+ RealFile::RDWR |
21
+ RealFile::APPEND |
22
+ RealFile::CREAT |
23
+ RealFile::EXCL |
24
+ RealFile::NONBLOCK |
25
+ RealFile::TRUNC |
26
+ RealFile::NOCTTY |
27
+ RealFile::SYNC
28
+
29
+ FILE_CREATION_BITMASK = RealFile::CREAT
30
+
31
+ def self.extname(path)
32
+ RealFile.extname(path)
33
+ end
34
+
35
+ def self.join(*parts)
36
+ RealFile.join(parts)
37
+ end
38
+
39
+ def self.exist?(path)
40
+ !!FileSystem.find(path)
41
+ end
42
+
43
+ class << self
44
+ alias_method :exists?, :exist?
45
+
46
+ # Assuming that everyone can read and write files
47
+ alias_method :readable?, :exist?
48
+ alias_method :writable?, :exist?
49
+ end
50
+
51
+ def self.mtime(path)
52
+ if exists?(path)
53
+ FileSystem.find(path).mtime
54
+ else
55
+ raise Errno::ENOENT
56
+ end
57
+ end
58
+
59
+ def self.ctime(path)
60
+ if exists?(path)
61
+ FileSystem.find(path).ctime
62
+ else
63
+ raise Errno::ENOENT
64
+ end
65
+ end
66
+
67
+ def self.utime(atime, mtime, *paths)
68
+ paths.each do |path|
69
+ if exists?(path)
70
+ FileSystem.find(path).mtime = mtime
71
+ else
72
+ raise Errno::ENOENT
73
+ end
74
+ end
75
+
76
+ paths.size
77
+ end
78
+
79
+ def self.size(path)
80
+ read(path).length
81
+ end
82
+
83
+ def self.size?(path)
84
+ if exists?(path) && !size(path).zero?
85
+ true
86
+ else
87
+ nil
88
+ end
89
+ end
90
+
91
+ def self.const_missing(name)
92
+ RealFile.const_get(name)
93
+ end
94
+
95
+ def self.directory?(path)
96
+ if path.respond_to? :entry
97
+ path.entry.is_a? FakeDir
98
+ else
99
+ result = FileSystem.find(path)
100
+ result ? result.entry.is_a?(FakeDir) : false
101
+ end
102
+ end
103
+
104
+ def self.symlink?(path)
105
+ if path.respond_to? :entry
106
+ path.is_a? FakeSymlink
107
+ else
108
+ FileSystem.find(path).is_a? FakeSymlink
109
+ end
110
+ end
111
+
112
+ def self.file?(path)
113
+ if path.respond_to? :entry
114
+ path.entry.is_a? FakeFile
115
+ else
116
+ result = FileSystem.find(path)
117
+ result ? result.entry.is_a?(FakeFile) : false
118
+ end
119
+ end
120
+
121
+ def self.expand_path(*args)
122
+ RealFile.expand_path(*args)
123
+ end
124
+
125
+ def self.basename(*args)
126
+ RealFile.basename(*args)
127
+ end
128
+
129
+ def self.dirname(path)
130
+ RealFile.dirname(path)
131
+ end
132
+
133
+ def self.readlink(path)
134
+ symlink = FileSystem.find(path)
135
+ FileSystem.find(symlink.target).to_s
136
+ end
137
+
138
+ def self.read(path)
139
+ file = new(path)
140
+ if file.exists?
141
+ file.read
142
+ else
143
+ raise Errno::ENOENT
144
+ end
145
+ end
146
+
147
+ def self.readlines(path)
148
+ read(path).split("\n")
149
+ end
150
+
151
+ def self.rename(source, dest)
152
+ if directory?(source) && file?(dest)
153
+ raise Errno::ENOTDIR, "Not a directory - #{source} or #{dest}"
154
+ elsif file?(source) && directory?(dest)
155
+ raise Errno::EISDIR, "Is a directory - #{source} or #{dest}"
156
+ end
157
+
158
+ if target = FileSystem.find(source)
159
+ FileSystem.add(dest, target.entry.clone)
160
+ FileSystem.delete(source)
161
+ else
162
+ raise Errno::ENOENT, "No such file or directory - #{source} or #{dest}"
163
+ end
164
+
165
+ 0
166
+ end
167
+
168
+ def self.link(source, dest)
169
+ if directory?(source)
170
+ raise Errno::EPERM, "Operation not permitted - #{source} or #{dest}"
171
+ end
172
+
173
+ if !exists?(source)
174
+ raise Errno::ENOENT, "No such file or directory - #{source} or #{dest}"
175
+ end
176
+
177
+ if exists?(dest)
178
+ raise Errno::EEXIST, "File exists - #{source} or #{dest}"
179
+ end
180
+
181
+ source = FileSystem.find(source)
182
+ dest = FileSystem.add(dest, source.entry.clone)
183
+ source.link(dest)
184
+
185
+ 0
186
+ end
187
+
188
+ def self.delete(file_name, *additional_file_names)
189
+ if !exists?(file_name)
190
+ raise Errno::ENOENT, "No such file or directory - #{file_name}"
191
+ end
192
+
193
+ FileUtils.rm(file_name)
194
+
195
+ additional_file_names.each do |file_name|
196
+ FileUtils.rm(file_name)
197
+ end
198
+
199
+ additional_file_names.size + 1
200
+ end
201
+
202
+ class << self
203
+ alias_method :unlink, :delete
204
+ end
205
+
206
+ def self.symlink(source, dest)
207
+ FileUtils.ln_s(source, dest)
208
+ end
209
+
210
+ def self.stat(file)
211
+ File::Stat.new(file)
212
+ end
213
+
214
+ def self.lstat(file)
215
+ File::Stat.new(file, true)
216
+ end
217
+
218
+ class Stat
219
+ attr_reader :ctime, :mtime
220
+
221
+ def initialize(file, __lstat = false)
222
+ if !File.exists?(file)
223
+ raise(Errno::ENOENT, "No such file or directory - #{file}")
224
+ end
225
+
226
+ @file = file
227
+ @fake_file = FileSystem.find(@file)
228
+ @__lstat = __lstat
229
+ @ctime = @fake_file.ctime
230
+ @mtime = @fake_file.mtime
231
+ end
232
+
233
+ def symlink?
234
+ File.symlink?(@file)
235
+ end
236
+
237
+ def directory?
238
+ File.directory?(@file)
239
+ end
240
+
241
+ def nlink
242
+ @fake_file.links.size
243
+ end
244
+
245
+ def size
246
+ if @__lstat && symlink?
247
+ @fake_file.target.size
248
+ else
249
+ File.size(@file)
250
+ end
251
+ end
252
+ end
253
+
254
+ attr_reader :path
255
+
256
+ def initialize(path, mode = READ_ONLY, perm = nil)
257
+ @path = path
258
+ @mode = mode
259
+ @file = FileSystem.find(path)
260
+ @autoclose = true
261
+
262
+ check_modes!
263
+
264
+ file_creation_mode? ? create_missing_file : check_file_existence!
265
+
266
+ super(@file.content, mode)
267
+ end
268
+
269
+ def exists?
270
+ true
271
+ end
272
+
273
+ alias_method :tell=, :pos=
274
+ alias_method :sysread, :read
275
+ alias_method :syswrite, :write
276
+
277
+ undef_method :closed_read?
278
+ undef_method :closed_write?
279
+ undef_method :length
280
+ undef_method :size
281
+ undef_method :string
282
+ undef_method :string=
283
+
284
+ def ioctl(integer_cmd, arg)
285
+ raise NotImplementedError
286
+ end
287
+
288
+ def read_nonblock(maxlen, outbuf = nil)
289
+ raise NotImplementedError
290
+ end
291
+
292
+ def stat
293
+ self.class.stat(@path)
294
+ end
295
+
296
+ def lstat
297
+ self.class.lstat(@path)
298
+ end
299
+
300
+ def sysseek(position, whence = SEEK_SET)
301
+ seek(position, whence)
302
+ pos
303
+ end
304
+
305
+ alias_method :to_i, :fileno
306
+
307
+ def to_io
308
+ self
309
+ end
310
+
311
+ def write_nonblock(string)
312
+ raise NotImplementedError
313
+ end
314
+
315
+ def readpartial(maxlen, outbuf = nil)
316
+ raise NotImplementedError
317
+ end
318
+
319
+ def atime
320
+ raise NotImplementedError
321
+ end
322
+
323
+ def chmod(mode_int)
324
+ raise NotImplementedError
325
+ end
326
+
327
+ def chown(owner_int, group_int)
328
+ raise NotImplementedError
329
+ end
330
+
331
+ def ctime
332
+ self.class.ctime(@path)
333
+ end
334
+
335
+ def flock(locking_constant)
336
+ raise NotImplementedError
337
+ end
338
+
339
+ def mtime
340
+ self.class.mtime(@path)
341
+ end
342
+
343
+ if RUBY_VERSION >= "1.9"
344
+ def binmode?
345
+ raise NotImplementedError
346
+ end
347
+
348
+ def close_on_exec=(bool)
349
+ raise NotImplementedError
350
+ end
351
+
352
+ def close_on_exec?
353
+ raise NotImplementedError
354
+ end
355
+
356
+ def to_path
357
+ raise NotImplementedError
358
+ end
359
+ end
360
+
361
+ if RUBY_VERSION >= "1.9.2"
362
+ attr_writer :autoclose
363
+
364
+ def autoclose?
365
+ @autoclose
366
+ end
367
+
368
+ alias_method :fdatasync, :flush
369
+
370
+ def size
371
+ File.size(@path)
372
+ end
373
+ end
374
+
375
+ private
376
+
377
+ def check_modes!
378
+ StringIO.new("", @mode)
379
+ end
380
+
381
+ def check_file_existence!
382
+ raise Errno::ENOENT, @path unless @file
383
+ end
384
+
385
+ def file_creation_mode?
386
+ mode_in?(FILE_CREATION_MODES) || mode_in_bitmask?(FILE_CREATION_BITMASK)
387
+ end
388
+
389
+ def mode_in?(list)
390
+ list.any? { |element| @mode.include?(element) } if @mode.respond_to?(:include?)
391
+ end
392
+
393
+ def mode_in_bitmask?(mask)
394
+ (@mode & mask) != 0 if @mode.is_a?(Integer)
395
+ end
396
+
397
+ def create_missing_file
398
+ if !File.exists?(@path)
399
+ @file = FileSystem.add(path, FakeFile.new)
400
+ end
401
+ end
402
+ end
403
+ end