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.
@@ -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