memfs 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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