memfs 0.0.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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +128 -0
- data/Rakefile +6 -0
- data/lib/fileutils.rb +1738 -0
- data/lib/memfs/dir.rb +33 -0
- data/lib/memfs/fake/directory.rb +51 -0
- data/lib/memfs/fake/entry.rb +73 -0
- data/lib/memfs/fake/file/content.rb +47 -0
- data/lib/memfs/fake/file.rb +36 -0
- data/lib/memfs/fake/symlink.rb +32 -0
- data/lib/memfs/file/stat.rb +48 -0
- data/lib/memfs/file.rb +284 -0
- data/lib/memfs/file_system.rb +157 -0
- data/lib/memfs/filesystem_access.rb +7 -0
- data/lib/memfs/version.rb +3 -0
- data/lib/memfs.rb +100 -0
- data/memfs.gemspec +29 -0
- data/spec/fileutils_spec.rb +961 -0
- data/spec/memfs/dir_spec.rb +104 -0
- data/spec/memfs/fake/directory_spec.rb +115 -0
- data/spec/memfs/fake/entry_spec.rb +140 -0
- data/spec/memfs/fake/file/content_spec.rb +154 -0
- data/spec/memfs/fake/file_spec.rb +37 -0
- data/spec/memfs/fake/symlink_spec.rb +43 -0
- data/spec/memfs/file/stat_spec.rb +209 -0
- data/spec/memfs/file_spec.rb +928 -0
- data/spec/memfs/file_system_spec.rb +393 -0
- data/spec/memfs_spec.rb +54 -0
- data/spec/spec_helper.rb +20 -0
- metadata +203 -0
@@ -0,0 +1,961 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FileUtils do
|
6
|
+
before :each do
|
7
|
+
MemFs::File.umask(0020)
|
8
|
+
MemFs.activate!
|
9
|
+
|
10
|
+
FileUtils.mkdir '/test'
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
MemFs.deactivate!
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.cd' do
|
18
|
+
it "changes the current working directory" do
|
19
|
+
FileUtils.cd '/test'
|
20
|
+
expect(FileUtils.pwd).to eq('/test')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns nil" do
|
24
|
+
expect(FileUtils.cd('/test')).to be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it "raises an error when the given path doesn't exist" do
|
28
|
+
expect { FileUtils.cd('/nowhere') }.to raise_error(Errno::ENOENT)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "raises an error when the given path is not a directory" do
|
32
|
+
FileUtils.touch('/test-file')
|
33
|
+
expect { FileUtils.cd('/test-file') }.to raise_error(Errno::ENOTDIR)
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when called with a block" do
|
37
|
+
it "changes current working directory for the block execution" do
|
38
|
+
FileUtils.cd '/test' do
|
39
|
+
expect(FileUtils.pwd).to eq('/test')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "resumes to the old working directory after the block execution finished" do
|
44
|
+
FileUtils.cd '/'
|
45
|
+
previous_dir = FileUtils.pwd
|
46
|
+
FileUtils.cd('/test') {}
|
47
|
+
expect(FileUtils.pwd).to eq(previous_dir)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when the destination is a symlink" do
|
52
|
+
before :each do
|
53
|
+
FileUtils.symlink('/test', '/test-link')
|
54
|
+
end
|
55
|
+
|
56
|
+
it "changes directory to the last target of the link chain" do
|
57
|
+
FileUtils.cd('/test-link')
|
58
|
+
expect(FileUtils.pwd).to eq('/test')
|
59
|
+
end
|
60
|
+
|
61
|
+
it "raises an error if the last target of the link chain doesn't exist" do
|
62
|
+
expect { FileUtils.cd('/nowhere-link') }.to raise_error(Errno::ENOENT)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '.chmod' do
|
68
|
+
it "changes permission bits on the named file to the bit pattern represented by mode" do
|
69
|
+
FileUtils.touch '/test-file'
|
70
|
+
FileUtils.chmod 0777, '/test-file'
|
71
|
+
expect(File.stat('/test-file').mode).to eq(0100777)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "changes permission bits on the named files (in list) to the bit pattern represented by mode" do
|
75
|
+
FileUtils.touch ['/test-file', '/test-file2']
|
76
|
+
FileUtils.chmod 0777, ['/test-file', '/test-file2']
|
77
|
+
expect(File.stat('/test-file2').mode).to eq(0100777)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "returns an array containing the file names" do
|
81
|
+
file_names = %w[/test-file /test-file2]
|
82
|
+
FileUtils.touch file_names
|
83
|
+
expect(FileUtils.chmod(0777, file_names)).to eq(file_names)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "raises an error if an entry does not exist" do
|
87
|
+
expect { FileUtils.chmod(0777, '/test-file') }.to raise_error(Errno::ENOENT)
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when the named file is a symlink" do
|
91
|
+
before :each do
|
92
|
+
FileUtils.touch '/test-file'
|
93
|
+
FileUtils.symlink '/test-file', '/test-link'
|
94
|
+
end
|
95
|
+
|
96
|
+
context "when File responds to lchmod" do
|
97
|
+
it "changes the mode on the link" do
|
98
|
+
FileUtils.chmod(0777, '/test-link')
|
99
|
+
expect(File.lstat('/test-link').mode).to eq(0100777)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "doesn't change the mode of the link's target" do
|
103
|
+
mode = File.lstat('/test-file').mode
|
104
|
+
FileUtils.chmod(0777, '/test-link')
|
105
|
+
expect(File.lstat('/test-file').mode).to eq(mode)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when File doesn't respond to lchmod" do
|
110
|
+
it "does nothing" do
|
111
|
+
FileUtils::Entry_.any_instance.stub(:have_lchmod?).and_return(false)
|
112
|
+
mode = File.lstat('/test-link').mode
|
113
|
+
FileUtils.chmod(0777, '/test-link')
|
114
|
+
expect(File.lstat('/test-link').mode).to eq(mode)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe '.chmod_R' do
|
121
|
+
before :each do
|
122
|
+
FileUtils.touch '/test/test-file'
|
123
|
+
end
|
124
|
+
|
125
|
+
it "changes the permission bits on the named entry" do
|
126
|
+
FileUtils.chmod_R(0777, '/test')
|
127
|
+
expect(File.stat('/test').mode).to eq(0100777)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "changes the permission bits on any sub-directory of the named entry" do
|
131
|
+
FileUtils.chmod_R(0777, '/')
|
132
|
+
expect(File.stat('/test').mode).to eq(0100777)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "changes the permission bits on any descendant file of the named entry" do
|
136
|
+
FileUtils.chmod_R(0777, '/')
|
137
|
+
expect(File.stat('/test/test-file').mode).to eq(0100777)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '.chown' do
|
142
|
+
it "changes owner on the named file" do
|
143
|
+
FileUtils.chown(42, nil, '/test')
|
144
|
+
expect(File.stat('/test').uid).to eq(42)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "changes owner on the named files (in list)" do
|
148
|
+
FileUtils.touch('/test-file')
|
149
|
+
FileUtils.chown(42, nil, ['/test', '/test-file'])
|
150
|
+
expect(File.stat('/test-file').uid).to eq(42)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "changes group on the named entry" do
|
154
|
+
FileUtils.chown(nil, 42, '/test')
|
155
|
+
expect(File.stat('/test').gid).to eq(42)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "changes group on the named entries in list" do
|
159
|
+
FileUtils.touch('/test-file')
|
160
|
+
FileUtils.chown(nil, 42, ['/test', '/test-file'])
|
161
|
+
expect(File.stat('/test-file').gid).to eq(42)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "doesn't change user if user is nil" do
|
165
|
+
FileUtils.chown(nil, 42, '/test')
|
166
|
+
expect(File.stat('/test').uid).not_to be(42)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "doesn't change group if group is nil" do
|
170
|
+
FileUtils.chown(42, nil, '/test')
|
171
|
+
expect(File.stat('/test').gid).not_to be(42)
|
172
|
+
end
|
173
|
+
|
174
|
+
context "when the name entry is a symlink" do
|
175
|
+
before :each do
|
176
|
+
FileUtils.touch '/test-file'
|
177
|
+
FileUtils.symlink '/test-file', '/test-link'
|
178
|
+
end
|
179
|
+
|
180
|
+
it "changes the owner on the last target of the link chain" do
|
181
|
+
FileUtils.chown(42, nil, '/test-link')
|
182
|
+
expect(File.stat('/test-file').uid).to eq(42)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "changes the group on the last target of the link chain" do
|
186
|
+
FileUtils.chown(nil, 42, '/test-link')
|
187
|
+
expect(File.stat('/test-file').gid).to eq(42)
|
188
|
+
end
|
189
|
+
|
190
|
+
it "doesn't change the owner of the symlink" do
|
191
|
+
FileUtils.chown(42, nil, '/test-link')
|
192
|
+
expect(File.lstat('/test-link').uid).not_to be(42)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "doesn't change the group of the symlink" do
|
196
|
+
FileUtils.chown(nil, 42, '/test-link')
|
197
|
+
expect(File.lstat('/test-link').gid).not_to be(42)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '.chown_R' do
|
203
|
+
before :each do
|
204
|
+
FileUtils.touch '/test/test-file'
|
205
|
+
end
|
206
|
+
|
207
|
+
it "changes the owner on the named entry" do
|
208
|
+
FileUtils.chown_R(42, nil, '/test')
|
209
|
+
expect(File.stat('/test').uid).to eq(42)
|
210
|
+
end
|
211
|
+
|
212
|
+
it "changes the group on the named entry" do
|
213
|
+
FileUtils.chown_R(nil, 42, '/test')
|
214
|
+
expect(File.stat('/test').gid).to eq(42)
|
215
|
+
end
|
216
|
+
|
217
|
+
it "changes the owner on any sub-directory of the named entry" do
|
218
|
+
FileUtils.chown_R(42, nil, '/')
|
219
|
+
expect(File.stat('/test').uid).to eq(42)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "changes the group on any sub-directory of the named entry" do
|
223
|
+
FileUtils.chown_R(nil, 42, '/')
|
224
|
+
expect(File.stat('/test').gid).to eq(42)
|
225
|
+
end
|
226
|
+
|
227
|
+
it "changes the owner on any descendant file of the named entry" do
|
228
|
+
FileUtils.chown_R(42, nil, '/')
|
229
|
+
expect(File.stat('/test/test-file').uid).to eq(42)
|
230
|
+
end
|
231
|
+
|
232
|
+
it "changes the group on any descendant file of the named entry" do
|
233
|
+
FileUtils.chown_R(nil, 42, '/')
|
234
|
+
expect(File.stat('/test/test-file').gid).to eq(42)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe '.cmp' do
|
239
|
+
it_behaves_like 'aliased method', :cmp, :compare_file
|
240
|
+
end
|
241
|
+
|
242
|
+
describe '.compare_file' do
|
243
|
+
it "returns true if the contents of a file A and a file B are identical" do
|
244
|
+
File.open('/test-file', 'w') { |f| f.puts "this is a test" }
|
245
|
+
File.open('/test-file2', 'w') { |f| f.puts "this is a test" }
|
246
|
+
|
247
|
+
expect(FileUtils.compare_file('/test-file', '/test-file2')).to be_true
|
248
|
+
end
|
249
|
+
|
250
|
+
it "returns false if the contents of a file A and a file B are not identical" do
|
251
|
+
File.open('/test-file', 'w') { |f| f.puts "this is a test" }
|
252
|
+
File.open('/test-file2', 'w') { |f| f.puts "this is not a test" }
|
253
|
+
|
254
|
+
expect(FileUtils.compare_file('/test-file', '/test-file2')).to be_false
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
describe '.compare_stream' do
|
259
|
+
it "returns true if the contents of a stream A and stream B are identical" do
|
260
|
+
File.open('/test-file', 'w') { |f| f.puts "this is a test" }
|
261
|
+
File.open('/test-file2', 'w') { |f| f.puts "this is a test" }
|
262
|
+
|
263
|
+
file1 = File.open('/test-file')
|
264
|
+
file2 = File.open('/test-file2')
|
265
|
+
|
266
|
+
expect(FileUtils.compare_stream(file1, file2)).to be_true
|
267
|
+
end
|
268
|
+
|
269
|
+
it "returns false if the contents of a stream A and stream B are not identical" do
|
270
|
+
File.open('/test-file', 'w') { |f| f.puts "this is a test" }
|
271
|
+
File.open('/test-file2', 'w') { |f| f.puts "this is not a test" }
|
272
|
+
|
273
|
+
file1 = File.open('/test-file')
|
274
|
+
file2 = File.open('/test-file2')
|
275
|
+
|
276
|
+
expect(FileUtils.compare_stream(file1, file2)).to be_false
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
describe '.copy' do
|
281
|
+
it_behaves_like 'aliased method', :copy, :cp
|
282
|
+
end
|
283
|
+
|
284
|
+
describe '.copy_entry' do
|
285
|
+
it "copies a file system entry +src+ to +dest+" do
|
286
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
287
|
+
FileUtils.copy_entry('/test-file', '/test-copy')
|
288
|
+
expect(File.read('/test-copy')).to eq("test\n")
|
289
|
+
end
|
290
|
+
|
291
|
+
it "preserves file types" do
|
292
|
+
FileUtils.touch('/test-file')
|
293
|
+
FileUtils.symlink('/test-file', '/test-link')
|
294
|
+
FileUtils.copy_entry('/test-link', '/test-copy')
|
295
|
+
expect(File.symlink?('/test-copy')).to be_true
|
296
|
+
end
|
297
|
+
|
298
|
+
context "when +src+ does not exist" do
|
299
|
+
it "raises an exception" do
|
300
|
+
expect {
|
301
|
+
FileUtils.copy_entry('/test-file', '/test-copy')
|
302
|
+
}.to raise_error(RuntimeError)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
context "when +preserve+ is true" do
|
307
|
+
let(:time) { Date.parse('2013-01-01') }
|
308
|
+
|
309
|
+
before :each do
|
310
|
+
FileUtils.touch('/test-file')
|
311
|
+
FileUtils.chown(1042, 1042, '/test-file')
|
312
|
+
FileUtils.chmod(0777, '/test-file')
|
313
|
+
fs.find('/test-file').mtime = time
|
314
|
+
FileUtils.copy_entry('/test-file', '/test-copy', true)
|
315
|
+
end
|
316
|
+
|
317
|
+
it "preserves owner" do
|
318
|
+
expect(File.stat('/test-copy').uid).to eq(1042)
|
319
|
+
end
|
320
|
+
|
321
|
+
it "preserves group" do
|
322
|
+
expect(File.stat('/test-copy').gid).to eq(1042)
|
323
|
+
end
|
324
|
+
|
325
|
+
it "preserves permissions" do
|
326
|
+
expect(File.stat('/test-copy').mode).to eq(0100777)
|
327
|
+
end
|
328
|
+
|
329
|
+
it "preserves modified time" do
|
330
|
+
expect(File.stat('/test-copy').mtime).to eq(time)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
context "when +dest+ already exists" do
|
335
|
+
it "overwrite it" do
|
336
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
337
|
+
FileUtils.touch('/test-copy')
|
338
|
+
FileUtils.copy_entry('/test-file', '/test-copy')
|
339
|
+
expect(File.read('/test-copy')).to eq("test\n")
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context "when +remove_destination+ is true" do
|
344
|
+
it "removes each destination file before copy" do
|
345
|
+
FileUtils.touch(['/test-file', '/test-copy'])
|
346
|
+
File.should_receive(:unlink).with('/test-copy')
|
347
|
+
FileUtils.copy_entry('/test-file', '/test-copy', false, false, true)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
context "when +src+ is a directory" do
|
352
|
+
it "copies its contents recursively" do
|
353
|
+
FileUtils.mkdir_p('/test-dir/test-sub-dir')
|
354
|
+
FileUtils.copy_entry('/test-dir', '/test-copy')
|
355
|
+
expect(Dir.exists?('/test-copy/test-sub-dir')).to be_true
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
describe '.copy_file' do
|
361
|
+
it "copies file contents of src to dest" do
|
362
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
363
|
+
FileUtils.copy_file('/test-file', '/test-file2')
|
364
|
+
expect(File.read('/test-file2')).to eq("test\n")
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe '.copy_stream' do
|
369
|
+
# This method is not implemented since it is delegated to the IO class.
|
370
|
+
end
|
371
|
+
|
372
|
+
describe '.cp' do
|
373
|
+
before :each do
|
374
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
375
|
+
end
|
376
|
+
|
377
|
+
it "copies a file content +src+ to +dest+" do
|
378
|
+
FileUtils.cp('/test-file', '/copy-file')
|
379
|
+
expect(File.read('/copy-file')).to eq("test\n")
|
380
|
+
end
|
381
|
+
|
382
|
+
context "when +src+ and +dest+ are the same file" do
|
383
|
+
it "raises an error" do
|
384
|
+
expect { FileUtils.cp('/test-file', '/test-file') }.to raise_error(ArgumentError)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
context "when +dest+ is a directory" do
|
389
|
+
it "copies +src+ to +dest/src+" do
|
390
|
+
FileUtils.mkdir('/dest')
|
391
|
+
FileUtils.cp('/test-file', '/dest/copy-file')
|
392
|
+
expect(File.read('/dest/copy-file')).to eq("test\n")
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
context "when src is a list of files" do
|
397
|
+
context "when +dest+ is not a directory" do
|
398
|
+
it "raises an error" do
|
399
|
+
FileUtils.touch(['/dest', '/test-file2'])
|
400
|
+
expect { FileUtils.cp(['/test-file', '/test-file2'], '/dest') }.to raise_error(Errno::ENOTDIR)
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
describe '.cp_r' do
|
407
|
+
it "copies +src+ to +dest+" do
|
408
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
409
|
+
|
410
|
+
FileUtils.cp_r('/test-file', '/copy-file')
|
411
|
+
expect(File.read('/copy-file')).to eq("test\n")
|
412
|
+
end
|
413
|
+
|
414
|
+
context "when +src+ is a directory" do
|
415
|
+
it "copies all its contents recursively" do
|
416
|
+
FileUtils.mkdir('/test/dir')
|
417
|
+
FileUtils.touch('/test/dir/file')
|
418
|
+
|
419
|
+
FileUtils.cp_r('/test', '/dest')
|
420
|
+
expect(File.exists?('/dest/dir/file')).to be_true
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
context "when +dest+ is a directory" do
|
425
|
+
it "copies +src+ to +dest/src+" do
|
426
|
+
FileUtils.mkdir(['/test/dir', '/dest'])
|
427
|
+
FileUtils.touch('/test/dir/file')
|
428
|
+
|
429
|
+
FileUtils.cp_r('/test', '/dest')
|
430
|
+
expect(File.exists?('/dest/test/dir/file')).to be_true
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
context "when +src+ is a list of files" do
|
435
|
+
it "copies each of them in +dest+" do
|
436
|
+
FileUtils.mkdir(['/test/dir', '/test/dir2', '/dest'])
|
437
|
+
FileUtils.touch(['/test/dir/file', '/test/dir2/file'])
|
438
|
+
|
439
|
+
FileUtils.cp_r(['/test/dir', '/test/dir2'], '/dest')
|
440
|
+
expect(File.exists?('/dest/dir2/file')).to be_true
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
describe '.getwd' do
|
446
|
+
it_behaves_like 'aliased method', :getwd, :pwd
|
447
|
+
end
|
448
|
+
|
449
|
+
describe '.identical?' do
|
450
|
+
it_behaves_like 'aliased method', :identical?, :compare_file
|
451
|
+
end
|
452
|
+
|
453
|
+
describe '.install' do
|
454
|
+
before :each do
|
455
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
456
|
+
end
|
457
|
+
|
458
|
+
it "copies +src+ to +dest+" do
|
459
|
+
FileUtils.install('/test-file', '/test-file2')
|
460
|
+
expect(File.read('/test-file2')).to eq("test\n")
|
461
|
+
end
|
462
|
+
|
463
|
+
context "when +:mode+ is set" do
|
464
|
+
it "changes the permission mode to +mode+" do
|
465
|
+
File.should_receive(:chmod).with(0777, '/test-file2')
|
466
|
+
FileUtils.install('/test-file', '/test-file2', mode: 0777)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
context "when +src+ and +dest+ are the same file" do
|
471
|
+
it "raises an exception" do
|
472
|
+
expect {
|
473
|
+
FileUtils.install('/test-file', '/test-file')
|
474
|
+
}.to raise_exception(ArgumentError)
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
context "when +dest+ already exists" do
|
479
|
+
it "removes destination before copy" do
|
480
|
+
File.should_receive(:unlink).with('/test-file2')
|
481
|
+
FileUtils.install('/test-file', '/test-file2')
|
482
|
+
end
|
483
|
+
|
484
|
+
context "and +dest+ is a directory" do
|
485
|
+
it "installs +src+ in dest/src" do
|
486
|
+
FileUtils.mkdir('/test-dir')
|
487
|
+
FileUtils.install('/test-file', '/test-dir')
|
488
|
+
expect(File.read('/test-dir/test-file')).to eq("test\n")
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
describe '.link' do
|
495
|
+
it_behaves_like 'aliased method', :link, :ln
|
496
|
+
end
|
497
|
+
|
498
|
+
describe '.ln' do
|
499
|
+
before :each do
|
500
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
501
|
+
end
|
502
|
+
|
503
|
+
it "creates a hard link +dest+ which points to +src+" do
|
504
|
+
FileUtils.ln('/test-file', '/test-file2')
|
505
|
+
expect(File.read('/test-file2')).to eq(File.read('/test-file'))
|
506
|
+
end
|
507
|
+
|
508
|
+
it "creates a hard link, not a symlink" do
|
509
|
+
FileUtils.ln('/test-file', '/test-file2')
|
510
|
+
expect(File.symlink?('/test-file2')).to be_false
|
511
|
+
end
|
512
|
+
|
513
|
+
context "when +dest+ already exists" do
|
514
|
+
context "and is a directory" do
|
515
|
+
it "creates a link dest/src" do
|
516
|
+
FileUtils.mkdir('/test-dir')
|
517
|
+
FileUtils.ln('/test-file', '/test-dir')
|
518
|
+
expect(File.read('/test-dir/test-file')).to eq(File.read('/test-file'))
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
context "and it is not a directory" do
|
523
|
+
it "raises an exception" do
|
524
|
+
FileUtils.touch('/test-file2')
|
525
|
+
expect { FileUtils.ln('/test-file', '/test-file2') }.to raise_error(SystemCallError)
|
526
|
+
end
|
527
|
+
|
528
|
+
context "and +:force+ is set" do
|
529
|
+
it "overwrites +dest+" do
|
530
|
+
FileUtils.touch('/test-file2')
|
531
|
+
FileUtils.ln('/test-file', '/test-file2', force: true)
|
532
|
+
expect(File.read('/test-file2')).to eq(File.read('/test-file'))
|
533
|
+
end
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
context "when passing a list of paths" do
|
539
|
+
it "creates a link for each path in +destdir+" do
|
540
|
+
FileUtils.touch('/test-file2')
|
541
|
+
FileUtils.mkdir('/test-dir')
|
542
|
+
FileUtils.ln(['/test-file', '/test-file2'], '/test-dir')
|
543
|
+
end
|
544
|
+
|
545
|
+
context "and +destdir+ is not a directory" do
|
546
|
+
it "raises an exception" do
|
547
|
+
FileUtils.touch(['/test-file2', '/not-a-dir'])
|
548
|
+
expect {
|
549
|
+
FileUtils.ln(['/test-file', '/test-file2'], '/not-a-dir')
|
550
|
+
}.to raise_error(Errno::ENOTDIR)
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
describe '.ln_s' do
|
557
|
+
before :each do
|
558
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
559
|
+
FileUtils.touch('/not-a-dir')
|
560
|
+
FileUtils.mkdir('/test-dir')
|
561
|
+
end
|
562
|
+
|
563
|
+
it "creates a symbolic link +new+" do
|
564
|
+
FileUtils.ln_s('/test-file', '/test-link')
|
565
|
+
expect(File.symlink?('/test-link')).to be_true
|
566
|
+
end
|
567
|
+
|
568
|
+
it "creates a symbolic link which points to +old+" do
|
569
|
+
FileUtils.ln_s('/test-file', '/test-link')
|
570
|
+
expect(File.read('/test-link')).to eq(File.read('/test-file'))
|
571
|
+
end
|
572
|
+
|
573
|
+
context "when +new+ already exists" do
|
574
|
+
context "and it is a directory" do
|
575
|
+
it "creates a symbolic link +new/old+" do
|
576
|
+
FileUtils.ln_s('/test-file', '/test-dir')
|
577
|
+
expect(File.symlink?('/test-dir/test-file')).to be_true
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
context "and it is not a directory" do
|
582
|
+
it "raises an exeption" do
|
583
|
+
expect {
|
584
|
+
FileUtils.ln_s('/test-file', '/not-a-dir')
|
585
|
+
}.to raise_error(Errno::EEXIST)
|
586
|
+
end
|
587
|
+
|
588
|
+
context "and +:force+ is set" do
|
589
|
+
it "overwrites +new+" do
|
590
|
+
FileUtils.ln_s('/test-file', '/not-a-dir', force: true)
|
591
|
+
expect(File.symlink?('/not-a-dir')).to be_true
|
592
|
+
end
|
593
|
+
end
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
context "when passing a list of paths" do
|
598
|
+
before :each do
|
599
|
+
File.open('/test-file2', 'w') { |f| f.puts 'test2' }
|
600
|
+
end
|
601
|
+
|
602
|
+
it "creates several symbolic links in +destdir+" do
|
603
|
+
FileUtils.ln_s(['/test-file', '/test-file2'], '/test-dir')
|
604
|
+
expect(File.exists?('/test-dir/test-file2')).to be_true
|
605
|
+
end
|
606
|
+
|
607
|
+
it "creates symbolic links pointing to each item in the list" do
|
608
|
+
FileUtils.ln_s(['/test-file', '/test-file2'], '/test-dir')
|
609
|
+
expect(File.read('/test-dir/test-file2')).to eq(File.read('/test-file2'))
|
610
|
+
end
|
611
|
+
|
612
|
+
context "when +destdir+ is not a directory" do
|
613
|
+
it "raises an error" do
|
614
|
+
expect {
|
615
|
+
FileUtils.ln_s(['/test-file', '/test-file2'], '/not-a-dir')
|
616
|
+
}.to raise_error(Errno::ENOTDIR)
|
617
|
+
end
|
618
|
+
end
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
describe '.ln_sf' do
|
623
|
+
it "calls ln_s with +:force+ set to true" do
|
624
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
625
|
+
File.open('/test-file2', 'w') { |f| f.puts 'test2' }
|
626
|
+
FileUtils.ln_sf('/test-file', '/test-file2')
|
627
|
+
expect(File.read('/test-file2')).to eq(File.read('/test-file'))
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
describe '.makedirs' do
|
632
|
+
it_behaves_like 'aliased method', :makedirs, :mkdir_p
|
633
|
+
end
|
634
|
+
|
635
|
+
describe '.mkdir' do
|
636
|
+
it "creates one directory" do
|
637
|
+
FileUtils.mkdir('/test-dir')
|
638
|
+
expect(File.directory?('/test-dir')).to be_true
|
639
|
+
end
|
640
|
+
|
641
|
+
context "when passing a list of paths" do
|
642
|
+
it "creates several directories" do
|
643
|
+
FileUtils.mkdir(['/test-dir', '/test-dir2'])
|
644
|
+
expect(File.directory?('/test-dir2')).to be_true
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
describe '.mkdir_p' do
|
650
|
+
it "creates a directory" do
|
651
|
+
FileUtils.mkdir_p('/test-dir')
|
652
|
+
expect(File.directory?('/test-dir')).to be_true
|
653
|
+
end
|
654
|
+
|
655
|
+
it "creates all the parent directories" do
|
656
|
+
FileUtils.mkdir_p('/path/to/some/test-dir')
|
657
|
+
expect(File.directory?('/path/to/some')).to be_true
|
658
|
+
end
|
659
|
+
|
660
|
+
context "when passing a list of paths" do
|
661
|
+
it "creates each directory" do
|
662
|
+
FileUtils.mkdir_p(['/test-dir', '/test-dir'])
|
663
|
+
expect(File.directory?('/test-dir')).to be_true
|
664
|
+
end
|
665
|
+
|
666
|
+
it "creates each directory's parents" do
|
667
|
+
FileUtils.mkdir_p(['/test-dir', '/path/to/some/test-dir'])
|
668
|
+
expect(File.directory?('/path/to/some')).to be_true
|
669
|
+
end
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
describe '.mkpath' do
|
674
|
+
it_behaves_like 'aliased method', :mkpath, :mkdir_p
|
675
|
+
end
|
676
|
+
|
677
|
+
describe '.move' do
|
678
|
+
it_behaves_like 'aliased method', :move, :mv
|
679
|
+
end
|
680
|
+
|
681
|
+
describe '.mv' do
|
682
|
+
it "moves +src+ to +dest+" do
|
683
|
+
FileUtils.touch('/test-file')
|
684
|
+
FileUtils.mv('/test-file', '/test-file2')
|
685
|
+
expect(File.exists?('/test-file2')).to be_true
|
686
|
+
end
|
687
|
+
|
688
|
+
it "removes +src+" do
|
689
|
+
FileUtils.touch('/test-file')
|
690
|
+
FileUtils.mv('/test-file', '/test-file2')
|
691
|
+
expect(File.exists?('/test-file')).to be_false
|
692
|
+
end
|
693
|
+
|
694
|
+
context "when +dest+ already exists" do
|
695
|
+
context "and is a directory" do
|
696
|
+
it "moves +src+ to dest/src" do
|
697
|
+
FileUtils.touch('/test-file')
|
698
|
+
FileUtils.mkdir('/test-dir')
|
699
|
+
FileUtils.mv('/test-file', '/test-dir')
|
700
|
+
expect(File.exists?('/test-dir/test-file')).to be_true
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
704
|
+
context "and +dest+ is not a directory" do
|
705
|
+
it "it overwrites +dest+" do
|
706
|
+
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
707
|
+
FileUtils.touch('/test-file2')
|
708
|
+
FileUtils.mv('/test-file', '/test-file2')
|
709
|
+
expect(File.read('/test-file2')).to eq("test\n")
|
710
|
+
end
|
711
|
+
end
|
712
|
+
end
|
713
|
+
end
|
714
|
+
|
715
|
+
describe '.pwd' do
|
716
|
+
it "returns the name of the current directory" do
|
717
|
+
FileUtils.cd '/test'
|
718
|
+
expect(FileUtils.pwd).to eq('/test')
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
describe '.remove' do
|
723
|
+
it_behaves_like 'aliased method', :remove, :rm
|
724
|
+
end
|
725
|
+
|
726
|
+
describe '.remove_dir' do
|
727
|
+
it "removes the given directory +dir+" do
|
728
|
+
FileUtils.mkdir('/test-dir')
|
729
|
+
FileUtils.remove_dir('/test-dir')
|
730
|
+
expect(File.exists?('/test-dir')).to be_false
|
731
|
+
end
|
732
|
+
|
733
|
+
it "removes the contents of the given directory +dir+" do
|
734
|
+
FileUtils.mkdir_p('/test-dir/test-sub-dir')
|
735
|
+
FileUtils.remove_dir('/test-dir')
|
736
|
+
expect(File.exists?('/test-dir/test-sub-dir')).to be_false
|
737
|
+
end
|
738
|
+
|
739
|
+
context "when +force+ is set" do
|
740
|
+
it "ignores standard errors" do
|
741
|
+
expect { FileUtils.remove_dir('/test-dir', true) }.not_to raise_error
|
742
|
+
end
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
describe '.remove_entry' do
|
747
|
+
it "removes a file system entry +path+" do
|
748
|
+
FileUtils.touch('/test-file')
|
749
|
+
FileUtils.remove_entry('/test-file')
|
750
|
+
expect(File.exists?('/test-file')).to be_false
|
751
|
+
end
|
752
|
+
|
753
|
+
context "when +path+ is a directory" do
|
754
|
+
it "removes it recursively" do
|
755
|
+
FileUtils.mkdir_p('/test-dir/test-sub-dir')
|
756
|
+
FileUtils.remove_entry('/test-dir')
|
757
|
+
expect(Dir.exists?('/test-dir')).to be_false
|
758
|
+
end
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
describe '.remove_entry_secure' do
|
763
|
+
before :each do
|
764
|
+
FileUtils.mkdir_p('/test-dir/test-sub-dir')
|
765
|
+
end
|
766
|
+
|
767
|
+
it "removes a file system entry +path+" do
|
768
|
+
FileUtils.chmod(0755, '/')
|
769
|
+
FileUtils.remove_entry_secure('/test-dir')
|
770
|
+
expect(Dir.exists?('/test-dir')).to be_false
|
771
|
+
end
|
772
|
+
|
773
|
+
context "when +path+ is a directory" do
|
774
|
+
it "removes it recursively" do
|
775
|
+
FileUtils.chmod(0755, '/')
|
776
|
+
FileUtils.remove_entry_secure('/test-dir')
|
777
|
+
expect(Dir.exists?('/test-dir/test-sub-dir')).to be_false
|
778
|
+
end
|
779
|
+
|
780
|
+
context "and is word writable" do
|
781
|
+
it "calls chown(2) on it" do
|
782
|
+
FileUtils.chmod(01777, '/')
|
783
|
+
directory = fs.find('/test-dir')
|
784
|
+
directory.should_receive(:uid=).at_least(:once)
|
785
|
+
FileUtils.remove_entry_secure('/test-dir')
|
786
|
+
end
|
787
|
+
|
788
|
+
it "calls chmod(2) on all sub directories" do
|
789
|
+
FileUtils.chmod(01777, '/')
|
790
|
+
directory = fs.find('/test-dir')
|
791
|
+
directory.should_receive(:mode=).at_least(:once)
|
792
|
+
FileUtils.remove_entry_secure('/test-dir')
|
793
|
+
end
|
794
|
+
end
|
795
|
+
end
|
796
|
+
end
|
797
|
+
|
798
|
+
describe '.remove_file' do
|
799
|
+
it "removes a file path" do
|
800
|
+
FileUtils.touch('/test-file')
|
801
|
+
FileUtils.remove_file('/test-file')
|
802
|
+
expect(File.exists?('/test-file')).to be_false
|
803
|
+
end
|
804
|
+
|
805
|
+
context "when +force+ is set" do
|
806
|
+
it "ignores StandardError" do
|
807
|
+
expect { FileUtils.remove_file('/no-file', true) }.not_to raise_error
|
808
|
+
end
|
809
|
+
end
|
810
|
+
end
|
811
|
+
|
812
|
+
describe '.rm' do
|
813
|
+
it "removes the specified file" do
|
814
|
+
FileUtils.touch('/test-file')
|
815
|
+
FileUtils.rm('/test-file')
|
816
|
+
expect(File.exists?('/test-file')).to be_false
|
817
|
+
end
|
818
|
+
|
819
|
+
it "removes files specified in list" do
|
820
|
+
FileUtils.touch(['/test-file', '/test-file2'])
|
821
|
+
FileUtils.rm(['/test-file', '/test-file2'])
|
822
|
+
expect(File.exists?('/test-file2')).to be_false
|
823
|
+
end
|
824
|
+
|
825
|
+
it "cannot remove a directory" do
|
826
|
+
FileUtils.mkdir('/test-dir')
|
827
|
+
expect { FileUtils.rm('/test-dir') }.to raise_error(Errno::EPERM)
|
828
|
+
end
|
829
|
+
|
830
|
+
context "when +:force+ is set" do
|
831
|
+
it "ignores StandardError" do
|
832
|
+
FileUtils.mkdir('/test-dir')
|
833
|
+
expect {
|
834
|
+
FileUtils.rm('/test-dir', force: true)
|
835
|
+
}.not_to raise_error(Errno::EPERM)
|
836
|
+
end
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
describe '.rm_f' do
|
841
|
+
it "calls rm with +:force+ set to true" do
|
842
|
+
FileUtils.should_receive(:rm).with('test', force: true)
|
843
|
+
FileUtils.rm_f('test')
|
844
|
+
end
|
845
|
+
end
|
846
|
+
|
847
|
+
describe '.rm_r' do
|
848
|
+
before :each do
|
849
|
+
FileUtils.touch(['/test-file', '/test-file2'])
|
850
|
+
end
|
851
|
+
|
852
|
+
it "removes a list of files" do
|
853
|
+
FileUtils.rm_r(['/test-file', '/test-file2'])
|
854
|
+
expect(File.exists?('/test-file2')).to be_false
|
855
|
+
end
|
856
|
+
|
857
|
+
context "when an item of the list is a directory" do
|
858
|
+
it "removes all its contents recursively" do
|
859
|
+
FileUtils.mkdir('/test-dir')
|
860
|
+
FileUtils.touch('/test-dir/test-file')
|
861
|
+
FileUtils.rm_r(['/test-file', '/test-file2', '/test-dir'])
|
862
|
+
expect(File.exists?('/test-dir/test-file')).to be_false
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
context "when +:force+ is set" do
|
867
|
+
it "ignores StandardError" do
|
868
|
+
expect {
|
869
|
+
FileUtils.rm_r(['/no-file'], force: true)
|
870
|
+
}.not_to raise_error(Errno::ENOENT)
|
871
|
+
end
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
875
|
+
describe '.rm_rf' do
|
876
|
+
it "calls rm with +:force+ set to true" do
|
877
|
+
FileUtils.should_receive(:rm_r).with('test', force: true)
|
878
|
+
FileUtils.rm_rf('test')
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
882
|
+
describe '.rmdir' do
|
883
|
+
it "Removes a directory" do
|
884
|
+
FileUtils.mkdir('/test-dir')
|
885
|
+
FileUtils.rmdir('/test-dir')
|
886
|
+
expect(Dir.exists?('/test-dir')).to be_false
|
887
|
+
end
|
888
|
+
|
889
|
+
it "Removes a list of directories" do
|
890
|
+
FileUtils.mkdir('/test-dir')
|
891
|
+
FileUtils.mkdir('/test-dir2')
|
892
|
+
FileUtils.rmdir(['/test-dir', '/test-dir2'])
|
893
|
+
expect(Dir.exists?('/test-dir2')).to be_false
|
894
|
+
end
|
895
|
+
|
896
|
+
context "when a directory is not empty" do
|
897
|
+
before :each do
|
898
|
+
FileUtils.mkdir('/test-dir')
|
899
|
+
FileUtils.touch('/test-dir/test-file')
|
900
|
+
end
|
901
|
+
|
902
|
+
it "ignores errors" do
|
903
|
+
expect { FileUtils.rmdir('/test-dir') }.not_to raise_error
|
904
|
+
end
|
905
|
+
|
906
|
+
it "doesn't remove the directory" do
|
907
|
+
FileUtils.rmdir('/test-dir')
|
908
|
+
expect(Dir.exists?('/test-dir')).to be_true
|
909
|
+
end
|
910
|
+
end
|
911
|
+
end
|
912
|
+
|
913
|
+
describe '.rmtree' do
|
914
|
+
it_behaves_like 'aliased method', :rmtree, :rm_rf
|
915
|
+
end
|
916
|
+
|
917
|
+
describe '.safe_unlink' do
|
918
|
+
it_behaves_like 'aliased method', :safe_unlink, :rm_f
|
919
|
+
end
|
920
|
+
|
921
|
+
describe '.symlink' do
|
922
|
+
it_behaves_like 'aliased method', :symlink, :ln_s
|
923
|
+
end
|
924
|
+
|
925
|
+
describe '.touch' do
|
926
|
+
it "creates a file if it doesn't exist" do
|
927
|
+
FileUtils.touch('/test-file')
|
928
|
+
expect(fs.find('/test-file')).not_to be_nil
|
929
|
+
end
|
930
|
+
|
931
|
+
it "creates a list of files if they don't exist" do
|
932
|
+
FileUtils.touch(['/test-file', '/test-file2'])
|
933
|
+
expect(fs.find('/test-file2')).not_to be_nil
|
934
|
+
end
|
935
|
+
end
|
936
|
+
|
937
|
+
describe '.uptodate?' do
|
938
|
+
before :each do
|
939
|
+
FileUtils.touch('/test-file')
|
940
|
+
FileUtils.touch('/old-file')
|
941
|
+
fs.find!('/old-file').mtime = Time.now - 3600
|
942
|
+
end
|
943
|
+
|
944
|
+
it "returns true if +newer+ is newer than all +old_list+" do
|
945
|
+
expect(FileUtils.uptodate?('/test-file', ['/old-file'])).to be_true
|
946
|
+
end
|
947
|
+
|
948
|
+
context "when +newer+ does not exist" do
|
949
|
+
it "consideres it as older" do
|
950
|
+
expect(FileUtils.uptodate?('/no-file', ['/old-file'])).to be_false
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
context "when a item of +old_list+ does not exist" do
|
955
|
+
it "consideres it as older than +newer+" do
|
956
|
+
uptodate = FileUtils.uptodate?('/test-file', ['/old-file', '/no-file'])
|
957
|
+
expect(uptodate).to be_true
|
958
|
+
end
|
959
|
+
end
|
960
|
+
end
|
961
|
+
end
|