mockfs 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mockfs.rb +351 -0
- data/lib/mockfs.rb~ +351 -0
- metadata +49 -0
data/lib/mockfs.rb
ADDED
@@ -0,0 +1,351 @@
|
|
1
|
+
# MockFS is a test-obsessed library for mocking out the entire file system.
|
2
|
+
# It provides mock objects that clone the functionality of File, FileUtils,
|
3
|
+
# Dir, and other in-Ruby file-access libraries.
|
4
|
+
#
|
5
|
+
# To use MockFS in your production code, call MockFS.get_[ class ].
|
6
|
+
#
|
7
|
+
# MockFS.get_file => File
|
8
|
+
# MockFS.get_file_utils => FileUtils
|
9
|
+
# MockFS.get_dir => Dir
|
10
|
+
# MockFS.get_dir.entries( '.' ) => [".", "..", ...]
|
11
|
+
#
|
12
|
+
# Then, to turn these into mock instances for a test case, simply call
|
13
|
+
#
|
14
|
+
# MockFS.mock = true
|
15
|
+
#
|
16
|
+
# When you've done this, the normal calls will actually return adapters that
|
17
|
+
# pretend to be the class in question:
|
18
|
+
#
|
19
|
+
# MockFS.get_file => MockFS::FileAdapter
|
20
|
+
# MockFS.get_file_utils => MockFS::FileUtilsAdapter
|
21
|
+
# MockFS.get_dir => MockFS::DirAdapter
|
22
|
+
# MockFS.get_dir.entries( '.' ) => [".", "..", ...]
|
23
|
+
#
|
24
|
+
# You can get direct access to the enclosed MockFileSystem by calling
|
25
|
+
# MockFS.mock_file_system.
|
26
|
+
#
|
27
|
+
# You can view the Rubyforge project page at
|
28
|
+
# http://rubyforge.org/projects/mockfs.
|
29
|
+
|
30
|
+
require 'delegate'
|
31
|
+
require 'extensions/all'
|
32
|
+
require 'fileutils'
|
33
|
+
require 'singleton'
|
34
|
+
|
35
|
+
module MockFS
|
36
|
+
Version = '0.1.1'
|
37
|
+
|
38
|
+
@@mock = false
|
39
|
+
|
40
|
+
def self.method_missing( symbol, *args ) #:nodoc:
|
41
|
+
class_name = nil
|
42
|
+
if symbol.id2name =~ /^get_(.*)/
|
43
|
+
class_name = $1.capitalize
|
44
|
+
class_name.gsub!( /_(\w)/ ) { |s| $1.capitalize }
|
45
|
+
unless %w( Dir File FileUtils ).include?( class_name )
|
46
|
+
class_name = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
if class_name
|
50
|
+
if @@mock
|
51
|
+
return_class = Class.by_name( 'MockFS::' + class_name + 'Adapter' )
|
52
|
+
else
|
53
|
+
return_class = Class.by_name( class_name )
|
54
|
+
end
|
55
|
+
return_class || super
|
56
|
+
elsif @@mock
|
57
|
+
mock_file_system.send( symbol, *args )
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Tell MockFS whether to offer interfaces to the real or mock file system.
|
64
|
+
# +is_mock+ should be a Boolean.
|
65
|
+
def self.mock= ( is_mock ); @@mock = is_mock; end
|
66
|
+
|
67
|
+
# If we're in mock mode, this will return the MockFileSystem; otherwise it
|
68
|
+
# will raise a RuntimeError.
|
69
|
+
def self.mock_file_system
|
70
|
+
@@mock ? MockFileSystem.instance : ( raise RuntimeError )
|
71
|
+
end
|
72
|
+
|
73
|
+
module Adapter #:nodoc:
|
74
|
+
@@delegated_methods = [ :delete, :entries, :mtime ]
|
75
|
+
|
76
|
+
def get_node( nodename ); MockFileSystem.instance.get_node( nodename ); end
|
77
|
+
|
78
|
+
def method_missing( sym, *args )
|
79
|
+
if @@delegated_methods.include?( sym )
|
80
|
+
get_node( args.first ).send( sym )
|
81
|
+
else
|
82
|
+
super
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def respond_to?( sym )
|
87
|
+
@@delegated_methods.include?( sym ) ? true : super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class DirAdapter #:nodoc:
|
92
|
+
extend Adapter
|
93
|
+
include Adapter
|
94
|
+
|
95
|
+
def self.mkdir( dirname )
|
96
|
+
path = Path.new( dirname ).absolute
|
97
|
+
get_node( path.parent ).mkdir( path.node )
|
98
|
+
end
|
99
|
+
|
100
|
+
def initialize( dirname )
|
101
|
+
unless get_node( dirname ).class == MockFileSystem::MockDir
|
102
|
+
raise Errno::ENOTDIR
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class FileAdapter #:nodoc:
|
108
|
+
extend Adapter
|
109
|
+
|
110
|
+
def self.chmod( perms, *filenames )
|
111
|
+
get_node( filenames.first ).permissions = perms
|
112
|
+
end
|
113
|
+
|
114
|
+
class << self
|
115
|
+
def exist?( filename )
|
116
|
+
begin
|
117
|
+
get_node( filename )
|
118
|
+
true
|
119
|
+
rescue Errno::ENOENT
|
120
|
+
false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
alias_method :exists?, :exist?
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.open( fd, mode_string = File::RDONLY, &action )
|
128
|
+
if mode_string.class == String
|
129
|
+
if mode_string == 'w'
|
130
|
+
mode_string = File::WRONLY
|
131
|
+
end
|
132
|
+
end
|
133
|
+
if mode_string == File::RDONLY
|
134
|
+
node = get_node( fd )
|
135
|
+
if node && node.permissions && node.permissions[0] == 0
|
136
|
+
raise Errno::EACCES
|
137
|
+
end
|
138
|
+
result = action.call( node )
|
139
|
+
node.rewind
|
140
|
+
result
|
141
|
+
else
|
142
|
+
path = Path.new( fd ).absolute
|
143
|
+
dir = get_node( path.parent )
|
144
|
+
if ( mode_string & File::APPEND > 0 )
|
145
|
+
mock_file = get_node( fd )
|
146
|
+
else
|
147
|
+
mock_file = MockFileSystem::MockFile.new( dir, path.node, '' )
|
148
|
+
end
|
149
|
+
if ( mode_string & File::APPEND == File::APPEND )
|
150
|
+
mock_file.pos = mock_file.size
|
151
|
+
end
|
152
|
+
action.call( mock_file )
|
153
|
+
mock_file.rewind
|
154
|
+
if ( mode_string & File::APPEND == 0 )
|
155
|
+
dir[path.node] = mock_file
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class FileUtilsAdapter #:nodoc:
|
162
|
+
extend Adapter
|
163
|
+
|
164
|
+
def self.cp( src, dest, options = {} )
|
165
|
+
file = get_node( src ).clone
|
166
|
+
dest_path = Path.new( dest ).absolute
|
167
|
+
dest_dir = get_node( dest_path.parent )
|
168
|
+
dest_dir[dest_path.node] = file
|
169
|
+
file.name = dest_path.node
|
170
|
+
file.parent = dest_dir
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.mv( src, dest, options = {} )
|
174
|
+
cp( src, dest, options )
|
175
|
+
MockFS.get_file.delete( src )
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.touch( file )
|
179
|
+
begin
|
180
|
+
get_node( file ).mtime = Time.now
|
181
|
+
rescue Errno::ENOENT
|
182
|
+
path = Path.new( file ).absolute
|
183
|
+
parent_dir = get_node( path.parent )
|
184
|
+
file = MockFileSystem::MockFile.new( parent_dir, path.node, nil )
|
185
|
+
parent_dir[path.node] = file
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# The MockFileSystem is the singleton class that pretends to be the file system in mock mode. When it's first created, it fills in one path up to your real directory location; other paths will have to be filled by hand using +fill_path+.
|
191
|
+
class MockFileSystem
|
192
|
+
include Singleton
|
193
|
+
|
194
|
+
# Flushes all file information out of the MockFileSystem.
|
195
|
+
def self.flush; instance.flush; end
|
196
|
+
|
197
|
+
def initialize #:nodoc:
|
198
|
+
flush
|
199
|
+
end
|
200
|
+
|
201
|
+
# Flushes all file information out of the MockFileSystem.
|
202
|
+
def flush; @root = MockRoot.new( '' ); fill_path( '.' ); end
|
203
|
+
|
204
|
+
def get_node( dirname ) #:nodoc:
|
205
|
+
@root.get_node( dirname )
|
206
|
+
end
|
207
|
+
|
208
|
+
# Use this method to fill in directory paths. This is the same as calling mkdir a bunch of times.
|
209
|
+
#
|
210
|
+
# MockFS.mock_file_system.fill_path '/usr/local/bin'
|
211
|
+
# MockFS.mock_file_system.fill_path '/home/francis/Desktop/myproject/'
|
212
|
+
def fill_path( dirname )
|
213
|
+
@root.fill_path( Path.new( dirname ).absolute.strip )
|
214
|
+
end
|
215
|
+
|
216
|
+
module Node #:nodoc:
|
217
|
+
attr_accessor :mtime, :name, :parent, :permissions
|
218
|
+
end
|
219
|
+
|
220
|
+
class MockDir < DelegateClass( Hash ) #:nodoc:
|
221
|
+
include Node
|
222
|
+
|
223
|
+
def initialize( name, parent = nil )
|
224
|
+
super( {} )
|
225
|
+
@name, @parent = name, parent
|
226
|
+
@mtime = Time.now
|
227
|
+
end
|
228
|
+
|
229
|
+
def []= ( name, child )
|
230
|
+
super
|
231
|
+
@mtime = child.mtime
|
232
|
+
end
|
233
|
+
|
234
|
+
def delete( child = nil )
|
235
|
+
child ? super( child.name ) : parent.delete( self )
|
236
|
+
end
|
237
|
+
|
238
|
+
def entries; %w( . .. ).concat( keys ); end
|
239
|
+
|
240
|
+
def get_node( dirname )
|
241
|
+
if dirname.first == '..'
|
242
|
+
self.parent.get_node( dirname[1..-1] )
|
243
|
+
elsif dirname.first == '.'
|
244
|
+
self.get_node( dirname[1..-1] )
|
245
|
+
elsif dirname.size > 1
|
246
|
+
subdir = self[dirname.first]
|
247
|
+
subdir ? subdir.get_node( dirname[1..-1] ) : ( raise Errno::ENOENT )
|
248
|
+
elsif dirname == ''
|
249
|
+
self
|
250
|
+
else
|
251
|
+
self[dirname.strip] or ( raise Errno::ENOENT )
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def fill_dir( dirname )
|
256
|
+
dir = self[dirname]
|
257
|
+
if dir.nil?
|
258
|
+
dir = MockDir.new( dirname, self )
|
259
|
+
self[dirname] = dir
|
260
|
+
@mtime = dir.mtime
|
261
|
+
end
|
262
|
+
dir
|
263
|
+
end
|
264
|
+
|
265
|
+
def fill_path( dirname )
|
266
|
+
if dirname.size > 1
|
267
|
+
dir = fill_dir( dirname.first )
|
268
|
+
dir.fill_path( dirname[1..-1] )
|
269
|
+
else
|
270
|
+
fill_dir( dirname )
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def mkdir( dirname ); fill_path( Path.new( dirname ) ); end
|
275
|
+
end
|
276
|
+
|
277
|
+
class MockFile < DelegateClass( StringIO ) #:nodoc:
|
278
|
+
include Node
|
279
|
+
|
280
|
+
attr_writer :contents
|
281
|
+
|
282
|
+
def initialize( parent, name, contents )
|
283
|
+
@name = name; @parent = parent; @mtime = Time.now; @contents = contents
|
284
|
+
super( StringIO.new( contents ) ) if contents
|
285
|
+
end
|
286
|
+
|
287
|
+
def clone
|
288
|
+
rewind
|
289
|
+
clone = self.class.new( @parent, @name, gets( nil ) )
|
290
|
+
clone.mtime = @mtime
|
291
|
+
clone
|
292
|
+
end
|
293
|
+
|
294
|
+
def delete; parent.delete( self ); end
|
295
|
+
|
296
|
+
def gets( sep_string = $/ )
|
297
|
+
@contents ? super( sep_string ) : nil
|
298
|
+
end
|
299
|
+
|
300
|
+
def rewind; @contents ? super : nil; end
|
301
|
+
end
|
302
|
+
|
303
|
+
class MockRoot < MockDir #:nodoc:
|
304
|
+
def get_node( dirname )
|
305
|
+
begin
|
306
|
+
super( Path.new( dirname ).absolute.strip )
|
307
|
+
rescue Errno::ENOENT
|
308
|
+
raise Errno::ENOENT.new( dirname )
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
class Path < String #:nodoc:
|
315
|
+
@@getwd = nil
|
316
|
+
|
317
|
+
def self.getwd
|
318
|
+
@@getwd = Dir.getwd if @@getwd.nil?
|
319
|
+
@@getwd
|
320
|
+
end
|
321
|
+
|
322
|
+
def []( *args ); Path.new( self.split( "/" )[*args].join( "/" ) ); end
|
323
|
+
|
324
|
+
def absolute
|
325
|
+
if self =~ %r{^\w}
|
326
|
+
Path.new( File.join( self.class.getwd, self ) )
|
327
|
+
else
|
328
|
+
new_str = self.to_s
|
329
|
+
new_str.gsub!( %r{^\.\.}, self.class.getwd + '/..' )
|
330
|
+
new_str.gsub!( %r{^\.}, self.class.getwd )
|
331
|
+
Path.new( new_str )
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def first; self.split( "/" ).first; end
|
336
|
+
|
337
|
+
def parent
|
338
|
+
self =~ %r{^(.*)/(.*?)$}
|
339
|
+
$1
|
340
|
+
end
|
341
|
+
|
342
|
+
def node
|
343
|
+
self =~ %r{^(.*)/(.*?)$}
|
344
|
+
$2
|
345
|
+
end
|
346
|
+
|
347
|
+
def size; self.split( '/' ).size; end
|
348
|
+
|
349
|
+
def strip; self.gsub( %r{^/+}, '' ).gsub( %r{/+$}, '' ); end
|
350
|
+
end
|
351
|
+
end
|
data/lib/mockfs.rb~
ADDED
@@ -0,0 +1,351 @@
|
|
1
|
+
# MockFS is a test-obsessed library for mocking out the entire file system.
|
2
|
+
# It provides mock objects that clone the functionality of File, FileUtils,
|
3
|
+
# Dir, and other in-Ruby file-access libraries.
|
4
|
+
#
|
5
|
+
# To use MockFS in your production code, call MockFS.get_[ class ].
|
6
|
+
#
|
7
|
+
# MockFS.get_file => File
|
8
|
+
# MockFS.get_file_utils => FileUtils
|
9
|
+
# MockFS.get_dir => Dir
|
10
|
+
# MockFS.get_dir.entries( '.' ) => [".", "..", ...]
|
11
|
+
#
|
12
|
+
# Then, to turn these into mock instances for a test case, simply call
|
13
|
+
#
|
14
|
+
# MockFS.mock = true
|
15
|
+
#
|
16
|
+
# When you've done this, the normal calls will actually return adapters that
|
17
|
+
# pretend to be the class in question:
|
18
|
+
#
|
19
|
+
# MockFS.get_file => MockFS::FileAdapter
|
20
|
+
# MockFS.get_file_utils => MockFS::FileUtilsAdapter
|
21
|
+
# MockFS.get_dir => MockFS::DirAdapter
|
22
|
+
# MockFS.get_dir.entries( '.' ) => [".", "..", ...]
|
23
|
+
#
|
24
|
+
# You can get direct access to the enclosed MockFileSystem by calling
|
25
|
+
# MockFS.mock_file_system.
|
26
|
+
#
|
27
|
+
# You can view the Rubyforge project page at
|
28
|
+
# http://rubyforge.org/projects/mockfs.
|
29
|
+
|
30
|
+
require 'delegate'
|
31
|
+
require 'extensions/all'
|
32
|
+
require 'fileutils'
|
33
|
+
require 'singleton'
|
34
|
+
|
35
|
+
module MockFS
|
36
|
+
Version = '0.1.0'
|
37
|
+
|
38
|
+
@@mock = false
|
39
|
+
|
40
|
+
def self.method_missing( symbol, *args ) #:nodoc:
|
41
|
+
class_name = nil
|
42
|
+
if symbol.id2name =~ /^get_(.*)/
|
43
|
+
class_name = $1.capitalize
|
44
|
+
class_name.gsub!( /_(\w)/ ) { |s| $1.capitalize }
|
45
|
+
unless %w( Dir File FileUtils ).include?( class_name )
|
46
|
+
class_name = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
if class_name
|
50
|
+
if @@mock
|
51
|
+
return_class = Class.by_name( 'MockFS::' + class_name + 'Adapter' )
|
52
|
+
else
|
53
|
+
return_class = Class.by_name( class_name )
|
54
|
+
end
|
55
|
+
return_class || super
|
56
|
+
elsif @@mock
|
57
|
+
mock_file_system.send( symbol, *args )
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Tell MockFS whether to offer interfaces to the real or mock file system.
|
64
|
+
# +is_mock+ should be a Boolean.
|
65
|
+
def self.mock= ( is_mock ); @@mock = is_mock; end
|
66
|
+
|
67
|
+
# If we're in mock mode, this will return the MockFileSystem; otherwise it
|
68
|
+
# will raise a RuntimeError.
|
69
|
+
def self.mock_file_system
|
70
|
+
@@mock ? MockFileSystem.instance : ( raise RuntimeError )
|
71
|
+
end
|
72
|
+
|
73
|
+
module Adapter #:nodoc:
|
74
|
+
@@delegated_methods = [ :delete, :entries, :mtime ]
|
75
|
+
|
76
|
+
def get_node( nodename ); MockFileSystem.instance.get_node( nodename ); end
|
77
|
+
|
78
|
+
def method_missing( sym, *args )
|
79
|
+
if @@delegated_methods.include?( sym )
|
80
|
+
get_node( args.first ).send( sym )
|
81
|
+
else
|
82
|
+
super
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def respond_to?( sym )
|
87
|
+
@@delegated_methods.include?( sym ) ? true : super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class DirAdapter #:nodoc:
|
92
|
+
extend Adapter
|
93
|
+
include Adapter
|
94
|
+
|
95
|
+
def self.mkdir( dirname )
|
96
|
+
path = Path.new( dirname ).absolute
|
97
|
+
get_node( path.parent ).mkdir( path.node )
|
98
|
+
end
|
99
|
+
|
100
|
+
def initialize( dirname )
|
101
|
+
unless get_node( dirname ).class == MockFileSystem::MockDir
|
102
|
+
raise Errno::ENOTDIR
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class FileAdapter #:nodoc:
|
108
|
+
extend Adapter
|
109
|
+
|
110
|
+
def self.chmod( perms, *filenames )
|
111
|
+
get_node( filenames.first ).permissions = perms
|
112
|
+
end
|
113
|
+
|
114
|
+
class << self
|
115
|
+
def exist?( filename )
|
116
|
+
begin
|
117
|
+
get_node( filename )
|
118
|
+
true
|
119
|
+
rescue Errno::ENOENT
|
120
|
+
false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
alias_method :exists?, :exist?
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.open( fd, mode_string = File::RDONLY, &action )
|
128
|
+
if mode_string.class == String
|
129
|
+
if mode_string == 'w'
|
130
|
+
mode_string = File::WRONLY
|
131
|
+
end
|
132
|
+
end
|
133
|
+
if mode_string == File::RDONLY
|
134
|
+
node = get_node( fd )
|
135
|
+
if node && node.permissions && node.permissions[0] == 0
|
136
|
+
raise Errno::EACCES
|
137
|
+
end
|
138
|
+
result = action.call( node )
|
139
|
+
node.rewind
|
140
|
+
result
|
141
|
+
else
|
142
|
+
path = Path.new( fd ).absolute
|
143
|
+
dir = get_node( path.parent )
|
144
|
+
if ( mode_string & File::APPEND > 0 )
|
145
|
+
mock_file = get_node( fd )
|
146
|
+
else
|
147
|
+
mock_file = MockFileSystem::MockFile.new( dir, path.node, '' )
|
148
|
+
end
|
149
|
+
if ( mode_string & File::APPEND == File::APPEND )
|
150
|
+
mock_file.pos = mock_file.size
|
151
|
+
end
|
152
|
+
action.call( mock_file )
|
153
|
+
mock_file.rewind
|
154
|
+
if ( mode_string & File::APPEND == 0 )
|
155
|
+
dir[path.node] = mock_file
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class FileUtilsAdapter #:nodoc:
|
162
|
+
extend Adapter
|
163
|
+
|
164
|
+
def self.cp( src, dest, options = {} )
|
165
|
+
file = get_node( src ).clone
|
166
|
+
dest_path = Path.new( dest ).absolute
|
167
|
+
dest_dir = get_node( dest_path.parent )
|
168
|
+
dest_dir[dest_path.node] = file
|
169
|
+
file.name = dest_path.node
|
170
|
+
file.parent = dest_dir
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.mv( src, dest, options = {} )
|
174
|
+
cp( src, dest, options )
|
175
|
+
MockFS.get_file.delete( src )
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.touch( file )
|
179
|
+
begin
|
180
|
+
get_node( file ).mtime = Time.now
|
181
|
+
rescue Errno::ENOENT
|
182
|
+
path = Path.new( file ).absolute
|
183
|
+
parent_dir = get_node( path.parent )
|
184
|
+
file = MockFileSystem::MockFile.new( parent_dir, path.node, nil )
|
185
|
+
parent_dir[path.node] = file
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# The MockFileSystem is the singleton class that pretends to be the file system in mock mode. When it's first created, it fills in one path up to your real directory location; other paths will have to be filled by hand using +fill_path+.
|
191
|
+
class MockFileSystem
|
192
|
+
include Singleton
|
193
|
+
|
194
|
+
# Flushes all file information out of the MockFileSystem.
|
195
|
+
def self.flush; instance.flush; end
|
196
|
+
|
197
|
+
def initialize #:nodoc:
|
198
|
+
flush
|
199
|
+
end
|
200
|
+
|
201
|
+
# Flushes all file information out of the MockFileSystem.
|
202
|
+
def flush; @root = MockRoot.new( '' ); fill_path( '.' ); end
|
203
|
+
|
204
|
+
def get_node( dirname ) #:nodoc:
|
205
|
+
@root.get_node( dirname )
|
206
|
+
end
|
207
|
+
|
208
|
+
# Use this method to fill in directory paths. This is the same as calling mkdir a bunch of times.
|
209
|
+
#
|
210
|
+
# MockFS.mock_file_system.fill_path '/usr/local/bin'
|
211
|
+
# MockFS.mock_file_system.fill_path '/home/francis/Desktop/myproject/'
|
212
|
+
def fill_path( dirname )
|
213
|
+
@root.fill_path( Path.new( dirname ).absolute.strip )
|
214
|
+
end
|
215
|
+
|
216
|
+
module Node #:nodoc:
|
217
|
+
attr_accessor :mtime, :name, :parent, :permissions
|
218
|
+
end
|
219
|
+
|
220
|
+
class MockDir < DelegateClass( Hash ) #:nodoc:
|
221
|
+
include Node
|
222
|
+
|
223
|
+
def initialize( name, parent = nil )
|
224
|
+
super( {} )
|
225
|
+
@name, @parent = name, parent
|
226
|
+
@mtime = Time.now
|
227
|
+
end
|
228
|
+
|
229
|
+
def []= ( name, child )
|
230
|
+
super
|
231
|
+
@mtime = child.mtime
|
232
|
+
end
|
233
|
+
|
234
|
+
def delete( child = nil )
|
235
|
+
child ? super( child.name ) : parent.delete( self )
|
236
|
+
end
|
237
|
+
|
238
|
+
def entries; %w( . .. ).concat( keys ); end
|
239
|
+
|
240
|
+
def get_node( dirname )
|
241
|
+
if dirname.first == '..'
|
242
|
+
self.parent.get_node( dirname[1..-1] )
|
243
|
+
elsif dirname.first == '.'
|
244
|
+
self.get_node( dirname[1..-1] )
|
245
|
+
elsif dirname.size > 1
|
246
|
+
subdir = self[dirname.first]
|
247
|
+
subdir ? subdir.get_node( dirname[1..-1] ) : ( raise Errno::ENOENT )
|
248
|
+
elsif dirname == ''
|
249
|
+
self
|
250
|
+
else
|
251
|
+
self[dirname.strip] or ( raise Errno::ENOENT )
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def fill_dir( dirname )
|
256
|
+
dir = self[dirname]
|
257
|
+
if dir.nil?
|
258
|
+
dir = MockDir.new( dirname, self )
|
259
|
+
self[dirname] = dir
|
260
|
+
@mtime = dir.mtime
|
261
|
+
end
|
262
|
+
dir
|
263
|
+
end
|
264
|
+
|
265
|
+
def fill_path( dirname )
|
266
|
+
if dirname.size > 1
|
267
|
+
dir = fill_dir( dirname.first )
|
268
|
+
dir.fill_path( dirname[1..-1] )
|
269
|
+
else
|
270
|
+
fill_dir( dirname )
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def mkdir( dirname ); fill_path( Path.new( dirname ) ); end
|
275
|
+
end
|
276
|
+
|
277
|
+
class MockFile < DelegateClass( StringIO ) #:nodoc:
|
278
|
+
include Node
|
279
|
+
|
280
|
+
attr_writer :contents
|
281
|
+
|
282
|
+
def initialize( parent, name, contents )
|
283
|
+
@name = name; @parent = parent; @mtime = Time.now; @contents = contents
|
284
|
+
super( StringIO.new( contents ) ) if contents
|
285
|
+
end
|
286
|
+
|
287
|
+
def clone
|
288
|
+
rewind
|
289
|
+
clone = self.class.new( @parent, @name, gets( nil ) )
|
290
|
+
clone.mtime = @mtime
|
291
|
+
clone
|
292
|
+
end
|
293
|
+
|
294
|
+
def delete; parent.delete( self ); end
|
295
|
+
|
296
|
+
def gets( sep_string = $/ )
|
297
|
+
@contents ? super( sep_string ) : nil
|
298
|
+
end
|
299
|
+
|
300
|
+
def rewind; @contents ? super : nil; end
|
301
|
+
end
|
302
|
+
|
303
|
+
class MockRoot < MockDir #:nodoc:
|
304
|
+
def get_node( dirname )
|
305
|
+
begin
|
306
|
+
super( Path.new( dirname ).absolute.strip )
|
307
|
+
rescue Errno::ENOENT
|
308
|
+
raise Errno::ENOENT.new( dirname )
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
class Path < String #:nodoc:
|
315
|
+
@@getwd = nil
|
316
|
+
|
317
|
+
def self.getwd
|
318
|
+
@@getwd = Dir.getwd if @@getwd.nil?
|
319
|
+
@@getwd
|
320
|
+
end
|
321
|
+
|
322
|
+
def []( *args ); Path.new( self.split( "/" )[*args].join( "/" ) ); end
|
323
|
+
|
324
|
+
def absolute
|
325
|
+
if self =~ %r{^\w}
|
326
|
+
Path.new( File.join( self.class.getwd, self ) )
|
327
|
+
else
|
328
|
+
new_str = self.to_s
|
329
|
+
new_str.gsub!( %r{^\.\.}, self.class.getwd + '/..' )
|
330
|
+
new_str.gsub!( %r{^\.}, self.class.getwd )
|
331
|
+
Path.new( new_str )
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def first; self.split( "/" ).first; end
|
336
|
+
|
337
|
+
def parent
|
338
|
+
self =~ %r{^(.*)/(.*?)$}
|
339
|
+
$1
|
340
|
+
end
|
341
|
+
|
342
|
+
def node
|
343
|
+
self =~ %r{^(.*)/(.*?)$}
|
344
|
+
$2
|
345
|
+
end
|
346
|
+
|
347
|
+
def size; self.split( '/' ).size; end
|
348
|
+
|
349
|
+
def strip; self.gsub( %r{^/+}, '' ).gsub( %r{/+$}, '' ); end
|
350
|
+
end
|
351
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.1
|
3
|
+
specification_version: 1
|
4
|
+
name: mockfs
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.1
|
7
|
+
date: 2005-02-23
|
8
|
+
summary: MockFS is a test-obsessed library for mocking out the entire file system.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
author: Francis Hwang
|
12
|
+
email: sera@fhwang.net
|
13
|
+
homepage: http://mockfs.rubyforge.org/
|
14
|
+
rubyforge_project:
|
15
|
+
description: "MockFS is a test-obsessed library for mocking out the entire file system. It
|
16
|
+
provides mock objects that clone the functionality of File, FileUtils, Dir, and
|
17
|
+
other in-Ruby file-access libraries."
|
18
|
+
autorequire: mockfs
|
19
|
+
default_executable:
|
20
|
+
bindir: bin
|
21
|
+
has_rdoc: false
|
22
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
23
|
+
requirements:
|
24
|
+
-
|
25
|
+
- ">"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.0.0
|
28
|
+
version:
|
29
|
+
platform: ruby
|
30
|
+
files:
|
31
|
+
- lib/mockfs.rb
|
32
|
+
- lib/mockfs.rb~
|
33
|
+
test_files: []
|
34
|
+
rdoc_options: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
requirements: []
|
39
|
+
dependencies:
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: extensions
|
42
|
+
version_requirement:
|
43
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
44
|
+
requirements:
|
45
|
+
-
|
46
|
+
- ">"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 0.0.0
|
49
|
+
version:
|