memfs 0.5.0 → 2.0.0
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 +5 -5
- data/.github/dependabot.yml +19 -0
- data/.github/workflows/ci.yml +64 -0
- data/.gitignore +1 -0
- data/.rspec +2 -2
- data/.rubocop.yml +81 -12
- data/CHANGELOG.md +41 -10
- data/Gemfile +19 -0
- data/Guardfile +5 -3
- data/README.md +7 -6
- data/Rakefile +4 -2
- data/bin/_guard-core +16 -0
- data/bin/coverage_summary +51 -0
- data/bin/guard +16 -0
- data/bin/rake +16 -0
- data/bin/rspec +16 -0
- data/bin/rubocop +16 -0
- data/lib/memfs/dir.rb +86 -21
- data/lib/memfs/fake/directory.rb +31 -3
- data/lib/memfs/fake/entry.rb +41 -25
- data/lib/memfs/fake/file/content.rb +6 -5
- data/lib/memfs/fake/file.rb +6 -5
- data/lib/memfs/fake/symlink.rb +2 -0
- data/lib/memfs/file/stat.rb +21 -14
- data/lib/memfs/file.rb +92 -77
- data/lib/memfs/file_system.rb +17 -12
- data/lib/memfs/filesystem_access.rb +2 -0
- data/lib/memfs/io.rb +183 -153
- data/lib/memfs/version.rb +3 -1
- data/lib/memfs.rb +112 -5
- data/memfs.gemspec +0 -14
- data/spec/fileutils_spec.rb +86 -58
- data/spec/memfs/dir_spec.rb +175 -27
- data/spec/memfs/fake/directory_spec.rb +8 -4
- data/spec/memfs/fake/entry_spec.rb +16 -10
- data/spec/memfs/fake/file/content_spec.rb +1 -1
- data/spec/memfs/fake/file_spec.rb +1 -1
- data/spec/memfs/fake/symlink_spec.rb +3 -3
- data/spec/memfs/file/stat_spec.rb +30 -15
- data/spec/memfs/file_spec.rb +271 -104
- data/spec/memfs/file_system_spec.rb +20 -19
- data/spec/memfs_spec.rb +67 -2
- data/spec/spec_helper.rb +40 -23
- metadata +17 -135
- data/.travis.yml +0 -6
data/spec/fileutils_spec.rb
CHANGED
|
@@ -2,9 +2,9 @@ require 'date'
|
|
|
2
2
|
require 'fileutils'
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
|
-
describe FileUtils do
|
|
5
|
+
RSpec.describe FileUtils do
|
|
6
6
|
before :each do
|
|
7
|
-
MemFs::File.umask(
|
|
7
|
+
MemFs::File.umask(0o020)
|
|
8
8
|
MemFs.activate!
|
|
9
9
|
|
|
10
10
|
described_class.mkdir '/test'
|
|
@@ -17,26 +17,32 @@ describe FileUtils do
|
|
|
17
17
|
describe '.cd' do
|
|
18
18
|
it 'changes the current working directory' do
|
|
19
19
|
described_class.cd '/test'
|
|
20
|
-
expect(described_class.pwd).to eq('/test')
|
|
20
|
+
expect(described_class.pwd).to eq(expected_path('/test'))
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
if MemFs.ruby_version_gte?('2.6')
|
|
24
|
+
it 'returns 0' do
|
|
25
|
+
expect(described_class.cd('/test')).to eq 0
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
it 'returns nil' do
|
|
29
|
+
expect(described_class.cd('/test')).to be_nil
|
|
30
|
+
end
|
|
25
31
|
end
|
|
26
32
|
|
|
27
33
|
it "raises an error when the given path doesn't exist" do
|
|
28
|
-
expect { described_class.cd('/nowhere') }.to
|
|
34
|
+
expect { described_class.cd('/nowhere') }.to raise_error(Errno::ENOENT)
|
|
29
35
|
end
|
|
30
36
|
|
|
31
37
|
it 'raises an error when the given path is not a directory' do
|
|
32
38
|
described_class.touch('/test-file')
|
|
33
|
-
expect { described_class.cd('/test-file') }.to
|
|
39
|
+
expect { described_class.cd('/test-file') }.to raise_error(Errno::ENOTDIR)
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
context 'when called with a block' do
|
|
37
43
|
it 'changes current working directory for the block execution' do
|
|
38
44
|
described_class.cd '/test' do
|
|
39
|
-
expect(described_class.pwd).to eq('/test')
|
|
45
|
+
expect(described_class.pwd).to eq(expected_path('/test'))
|
|
40
46
|
end
|
|
41
47
|
end
|
|
42
48
|
|
|
@@ -53,11 +59,11 @@ describe FileUtils do
|
|
|
53
59
|
|
|
54
60
|
it 'changes directory to the last target of the link chain' do
|
|
55
61
|
described_class.cd('/test-link')
|
|
56
|
-
expect(described_class.pwd).to eq('/test')
|
|
62
|
+
expect(described_class.pwd).to eq(expected_path('/test'))
|
|
57
63
|
end
|
|
58
64
|
|
|
59
65
|
it "raises an error if the last target of the link chain doesn't exist" do
|
|
60
|
-
expect { described_class.cd('/nowhere-link') }.to
|
|
66
|
+
expect { described_class.cd('/nowhere-link') }.to raise_error(Errno::ENOENT)
|
|
61
67
|
end
|
|
62
68
|
end
|
|
63
69
|
end
|
|
@@ -65,24 +71,24 @@ describe FileUtils do
|
|
|
65
71
|
describe '.chmod' do
|
|
66
72
|
it 'changes permission bits on the named file to the bit pattern represented by mode' do
|
|
67
73
|
described_class.touch '/test-file'
|
|
68
|
-
described_class.chmod
|
|
69
|
-
expect(File.stat('/test-file').mode).to eq(
|
|
74
|
+
described_class.chmod 0o777, '/test-file'
|
|
75
|
+
expect(File.stat('/test-file').mode).to eq(0o100777)
|
|
70
76
|
end
|
|
71
77
|
|
|
72
78
|
it 'changes permission bits on the named files (in list) to the bit pattern represented by mode' do
|
|
73
79
|
described_class.touch ['/test-file', '/test-file2']
|
|
74
|
-
described_class.chmod
|
|
75
|
-
expect(File.stat('/test-file2').mode).to eq(
|
|
80
|
+
described_class.chmod 0o777, ['/test-file', '/test-file2']
|
|
81
|
+
expect(File.stat('/test-file2').mode).to eq(0o100777)
|
|
76
82
|
end
|
|
77
83
|
|
|
78
84
|
it 'returns an array containing the file names' do
|
|
79
85
|
file_names = %w[/test-file /test-file2]
|
|
80
86
|
described_class.touch file_names
|
|
81
|
-
expect(described_class.chmod(
|
|
87
|
+
expect(described_class.chmod(0o777, file_names)).to eq(file_names)
|
|
82
88
|
end
|
|
83
89
|
|
|
84
90
|
it 'raises an error if an entry does not exist' do
|
|
85
|
-
expect { described_class.chmod(
|
|
91
|
+
expect { described_class.chmod(0o777, '/test-file') }.to raise_error(Errno::ENOENT)
|
|
86
92
|
end
|
|
87
93
|
|
|
88
94
|
context 'when the named file is a symlink' do
|
|
@@ -93,13 +99,13 @@ describe FileUtils do
|
|
|
93
99
|
|
|
94
100
|
context 'when File responds to lchmod' do
|
|
95
101
|
it 'changes the mode on the link' do
|
|
96
|
-
described_class.chmod(
|
|
97
|
-
expect(File.lstat('/test-link').mode).to eq(
|
|
102
|
+
described_class.chmod(0o777, '/test-link')
|
|
103
|
+
expect(File.lstat('/test-link').mode).to eq(0o100777)
|
|
98
104
|
end
|
|
99
105
|
|
|
100
106
|
it "doesn't change the mode of the link's target" do
|
|
101
107
|
mode = File.lstat('/test-file').mode
|
|
102
|
-
described_class.chmod(
|
|
108
|
+
described_class.chmod(0o777, '/test-link')
|
|
103
109
|
expect(File.lstat('/test-file').mode).to eq(mode)
|
|
104
110
|
end
|
|
105
111
|
end
|
|
@@ -109,7 +115,7 @@ describe FileUtils do
|
|
|
109
115
|
allow_any_instance_of(described_class::Entry_).to \
|
|
110
116
|
receive_messages(have_lchmod?: false)
|
|
111
117
|
mode = File.lstat('/test-link').mode
|
|
112
|
-
described_class.chmod(
|
|
118
|
+
described_class.chmod(0o777, '/test-link')
|
|
113
119
|
expect(File.lstat('/test-link').mode).to eq(mode)
|
|
114
120
|
end
|
|
115
121
|
end
|
|
@@ -122,18 +128,18 @@ describe FileUtils do
|
|
|
122
128
|
end
|
|
123
129
|
|
|
124
130
|
it 'changes the permission bits on the named entry' do
|
|
125
|
-
described_class.chmod_R(
|
|
126
|
-
expect(File.stat('/test').mode).to eq(
|
|
131
|
+
described_class.chmod_R(0o777, '/test')
|
|
132
|
+
expect(File.stat('/test').mode).to eq(0o100777)
|
|
127
133
|
end
|
|
128
134
|
|
|
129
135
|
it 'changes the permission bits on any sub-directory of the named entry' do
|
|
130
|
-
described_class.chmod_R(
|
|
131
|
-
expect(File.stat('/test').mode).to eq(
|
|
136
|
+
described_class.chmod_R(0o777, '/')
|
|
137
|
+
expect(File.stat('/test').mode).to eq(0o100777)
|
|
132
138
|
end
|
|
133
139
|
|
|
134
140
|
it 'changes the permission bits on any descendant file of the named entry' do
|
|
135
|
-
described_class.chmod_R(
|
|
136
|
-
expect(File.stat('/test/test-file').mode).to eq(
|
|
141
|
+
described_class.chmod_R(0o777, '/')
|
|
142
|
+
expect(File.stat('/test/test-file').mode).to eq(0o100777)
|
|
137
143
|
end
|
|
138
144
|
end
|
|
139
145
|
|
|
@@ -296,9 +302,12 @@ describe FileUtils do
|
|
|
296
302
|
|
|
297
303
|
context 'when +src+ does not exist' do
|
|
298
304
|
it 'raises an exception' do
|
|
305
|
+
expected_exception =
|
|
306
|
+
RUBY_VERSION >= '2.4.0' ? Errno::ENOENT : RuntimeError
|
|
307
|
+
|
|
299
308
|
expect {
|
|
300
309
|
described_class.copy_entry('/test-file', '/test-copy')
|
|
301
|
-
}.to
|
|
310
|
+
}.to raise_error(expected_exception)
|
|
302
311
|
end
|
|
303
312
|
end
|
|
304
313
|
|
|
@@ -308,7 +317,7 @@ describe FileUtils do
|
|
|
308
317
|
before :each do
|
|
309
318
|
described_class.touch('/test-file')
|
|
310
319
|
described_class.chown(1042, 1042, '/test-file')
|
|
311
|
-
described_class.chmod(
|
|
320
|
+
described_class.chmod(0o777, '/test-file')
|
|
312
321
|
_fs.find('/test-file').mtime = time
|
|
313
322
|
described_class.copy_entry('/test-file', '/test-copy', true)
|
|
314
323
|
end
|
|
@@ -322,7 +331,7 @@ describe FileUtils do
|
|
|
322
331
|
end
|
|
323
332
|
|
|
324
333
|
it 'preserves permissions' do
|
|
325
|
-
expect(File.stat('/test-copy').mode).to eq(
|
|
334
|
+
expect(File.stat('/test-copy').mode).to eq(0o100777)
|
|
326
335
|
end
|
|
327
336
|
|
|
328
337
|
it 'preserves modified time' do
|
|
@@ -382,7 +391,7 @@ describe FileUtils do
|
|
|
382
391
|
it 'raises an error' do
|
|
383
392
|
expect {
|
|
384
393
|
described_class.cp('/test-file', '/test-file')
|
|
385
|
-
}.to
|
|
394
|
+
}.to raise_error(ArgumentError)
|
|
386
395
|
end
|
|
387
396
|
end
|
|
388
397
|
|
|
@@ -400,7 +409,7 @@ describe FileUtils do
|
|
|
400
409
|
described_class.touch(['/dest', '/test-file2'])
|
|
401
410
|
expect {
|
|
402
411
|
described_class.cp(['/test-file', '/test-file2'], '/dest')
|
|
403
|
-
}.to
|
|
412
|
+
}.to raise_error(Errno::ENOTDIR)
|
|
404
413
|
end
|
|
405
414
|
end
|
|
406
415
|
end
|
|
@@ -465,8 +474,8 @@ describe FileUtils do
|
|
|
465
474
|
|
|
466
475
|
context 'when +:mode+ is set' do
|
|
467
476
|
it 'changes the permission mode to +mode+' do
|
|
468
|
-
expect(File).to receive(:chmod).with(
|
|
469
|
-
described_class.install('/test-file', '/test-file2', mode:
|
|
477
|
+
expect(File).to receive(:chmod).with(0o777, '/test-file2')
|
|
478
|
+
described_class.install('/test-file', '/test-file2', mode: 0o777)
|
|
470
479
|
end
|
|
471
480
|
end
|
|
472
481
|
|
|
@@ -474,7 +483,7 @@ describe FileUtils do
|
|
|
474
483
|
it 'raises an exception' do
|
|
475
484
|
expect {
|
|
476
485
|
described_class.install('/test-file', '/test-file')
|
|
477
|
-
}.to
|
|
486
|
+
}.to raise_error ArgumentError
|
|
478
487
|
end
|
|
479
488
|
end
|
|
480
489
|
|
|
@@ -527,7 +536,7 @@ describe FileUtils do
|
|
|
527
536
|
described_class.touch('/test-file2')
|
|
528
537
|
expect {
|
|
529
538
|
described_class.ln('/test-file', '/test-file2')
|
|
530
|
-
}.to
|
|
539
|
+
}.to raise_error(SystemCallError)
|
|
531
540
|
end
|
|
532
541
|
|
|
533
542
|
context 'and +:force+ is set' do
|
|
@@ -552,7 +561,7 @@ describe FileUtils do
|
|
|
552
561
|
described_class.touch(['/test-file2', '/not-a-dir'])
|
|
553
562
|
expect {
|
|
554
563
|
described_class.ln(['/test-file', '/test-file2'], '/not-a-dir')
|
|
555
|
-
}.to
|
|
564
|
+
}.to raise_error(Errno::ENOTDIR)
|
|
556
565
|
end
|
|
557
566
|
end
|
|
558
567
|
end
|
|
@@ -587,7 +596,7 @@ describe FileUtils do
|
|
|
587
596
|
it 'raises an exeption' do
|
|
588
597
|
expect {
|
|
589
598
|
described_class.ln_s('/test-file', '/not-a-dir')
|
|
590
|
-
}.to
|
|
599
|
+
}.to raise_error(Errno::EEXIST)
|
|
591
600
|
end
|
|
592
601
|
|
|
593
602
|
context 'and +:force+ is set' do
|
|
@@ -618,7 +627,7 @@ describe FileUtils do
|
|
|
618
627
|
it 'raises an error' do
|
|
619
628
|
expect {
|
|
620
629
|
described_class.ln_s(['/test-file', '/test-file2'], '/not-a-dir')
|
|
621
|
-
}.to
|
|
630
|
+
}.to raise_error(Errno::ENOTDIR)
|
|
622
631
|
end
|
|
623
632
|
end
|
|
624
633
|
end
|
|
@@ -653,9 +662,9 @@ describe FileUtils do
|
|
|
653
662
|
context 'when passing options' do
|
|
654
663
|
context 'when passing mode parameter' do
|
|
655
664
|
it 'creates directory with specified permissions' do
|
|
656
|
-
described_class.mkdir('/test-dir', mode:
|
|
665
|
+
described_class.mkdir('/test-dir', mode: 0o654)
|
|
657
666
|
expect(File.exist?('/test-dir')).to be true
|
|
658
|
-
expect(File.stat('/test-dir').mode).to eq(
|
|
667
|
+
expect(File.stat('/test-dir').mode).to eq(0o100654)
|
|
659
668
|
end
|
|
660
669
|
end
|
|
661
670
|
|
|
@@ -667,8 +676,6 @@ describe FileUtils do
|
|
|
667
676
|
end
|
|
668
677
|
end
|
|
669
678
|
end
|
|
670
|
-
|
|
671
|
-
|
|
672
679
|
end
|
|
673
680
|
|
|
674
681
|
describe '.mkdir_p' do
|
|
@@ -697,9 +704,9 @@ describe FileUtils do
|
|
|
697
704
|
context 'when passing options' do
|
|
698
705
|
context 'when passing mode parameter' do
|
|
699
706
|
it 'creates directory with specified permissions' do
|
|
700
|
-
described_class.mkdir_p('/test-dir', mode:
|
|
707
|
+
described_class.mkdir_p('/test-dir', mode: 0o654)
|
|
701
708
|
expect(File.exist?('/test-dir')).to be true
|
|
702
|
-
expect(File.stat('/test-dir').mode).to eq(
|
|
709
|
+
expect(File.stat('/test-dir').mode).to eq(0o100654)
|
|
703
710
|
end
|
|
704
711
|
end
|
|
705
712
|
|
|
@@ -758,7 +765,7 @@ describe FileUtils do
|
|
|
758
765
|
describe '.pwd' do
|
|
759
766
|
it 'returns the name of the current directory' do
|
|
760
767
|
described_class.cd '/test'
|
|
761
|
-
expect(described_class.pwd).to eq('/test')
|
|
768
|
+
expect(described_class.pwd).to eq(expected_path('/test'))
|
|
762
769
|
end
|
|
763
770
|
end
|
|
764
771
|
|
|
@@ -808,28 +815,28 @@ describe FileUtils do
|
|
|
808
815
|
end
|
|
809
816
|
|
|
810
817
|
it 'removes a file system entry +path+' do
|
|
811
|
-
described_class.chmod(
|
|
818
|
+
described_class.chmod(0o755, '/')
|
|
812
819
|
described_class.remove_entry_secure('/test-dir')
|
|
813
820
|
expect(Dir.exist?('/test-dir')).to be false
|
|
814
821
|
end
|
|
815
822
|
|
|
816
823
|
context 'when +path+ is a directory' do
|
|
817
824
|
it 'removes it recursively' do
|
|
818
|
-
described_class.chmod(
|
|
825
|
+
described_class.chmod(0o755, '/')
|
|
819
826
|
described_class.remove_entry_secure('/test-dir')
|
|
820
827
|
expect(Dir.exist?('/test-dir/test-sub-dir')).to be false
|
|
821
828
|
end
|
|
822
829
|
|
|
823
830
|
context 'and is word writable' do
|
|
824
831
|
it 'calls chown(2) on it' do
|
|
825
|
-
described_class.chmod(
|
|
832
|
+
described_class.chmod(0o1777, '/')
|
|
826
833
|
directory = _fs.find('/test-dir')
|
|
827
834
|
expect(directory).to receive(:uid=).at_least(:once)
|
|
828
835
|
described_class.remove_entry_secure('/test-dir')
|
|
829
836
|
end
|
|
830
837
|
|
|
831
838
|
it 'calls chmod(2) on all sub directories' do
|
|
832
|
-
described_class.chmod(
|
|
839
|
+
described_class.chmod(0o1777, '/')
|
|
833
840
|
directory = _fs.find('/test-dir')
|
|
834
841
|
expect(directory).to receive(:mode=).at_least(:once)
|
|
835
842
|
described_class.remove_entry_secure('/test-dir')
|
|
@@ -867,7 +874,7 @@ describe FileUtils do
|
|
|
867
874
|
|
|
868
875
|
it 'cannot remove a directory' do
|
|
869
876
|
described_class.mkdir('/test-dir')
|
|
870
|
-
expect { described_class.rm('/test-dir') }.to
|
|
877
|
+
expect { described_class.rm('/test-dir') }.to raise_error(Errno::EPERM)
|
|
871
878
|
end
|
|
872
879
|
|
|
873
880
|
context 'when +:force+ is set' do
|
|
@@ -882,7 +889,9 @@ describe FileUtils do
|
|
|
882
889
|
|
|
883
890
|
describe '.rm_f' do
|
|
884
891
|
it 'calls rm with +:force+ set to true' do
|
|
885
|
-
expect(described_class)
|
|
892
|
+
expect(described_class)
|
|
893
|
+
.to receive(:rm).with('test', a_hash_including(force: true))
|
|
894
|
+
|
|
886
895
|
described_class.rm_f('test')
|
|
887
896
|
end
|
|
888
897
|
end
|
|
@@ -917,7 +926,9 @@ describe FileUtils do
|
|
|
917
926
|
|
|
918
927
|
describe '.rm_rf' do
|
|
919
928
|
it 'calls rm with +:force+ set to true' do
|
|
920
|
-
expect(described_class)
|
|
929
|
+
expect(described_class)
|
|
930
|
+
.to receive(:rm_r).with('test', a_hash_including(force: true))
|
|
931
|
+
|
|
921
932
|
described_class.rm_rf('test')
|
|
922
933
|
end
|
|
923
934
|
end
|
|
@@ -942,13 +953,30 @@ describe FileUtils do
|
|
|
942
953
|
described_class.touch('/test-dir/test-file')
|
|
943
954
|
end
|
|
944
955
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
956
|
+
if RUBY_VERSION >= '2.5.0'
|
|
957
|
+
it 'raises an error' do
|
|
958
|
+
expect { described_class.rmdir('/test-dir') }
|
|
959
|
+
.to raise_error(Errno::ENOTEMPTY)
|
|
960
|
+
end
|
|
961
|
+
|
|
962
|
+
it 'doesn’t remove the directory' do
|
|
963
|
+
begin
|
|
964
|
+
described_class.rmdir('/test-dir')
|
|
965
|
+
rescue Errno::ENOTEMPTY
|
|
966
|
+
# noop
|
|
967
|
+
end
|
|
948
968
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
969
|
+
expect(Dir.exist?('/test-dir')).to be true
|
|
970
|
+
end
|
|
971
|
+
else
|
|
972
|
+
it 'ignores errors' do
|
|
973
|
+
expect { described_class.rmdir('/test-dir') }.not_to raise_error
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
it 'doesn’t remove the directory' do
|
|
977
|
+
described_class.rmdir('/test-dir')
|
|
978
|
+
expect(Dir.exist?('/test-dir')).to be true
|
|
979
|
+
end
|
|
952
980
|
end
|
|
953
981
|
end
|
|
954
982
|
end
|