memfs 0.0.2 → 0.1.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.
@@ -14,6 +14,31 @@ module MemFs
14
14
  subject.symlink '/no-file', '/no-link'
15
15
  end
16
16
 
17
+ describe '.absolute_path' do
18
+ before :each do
19
+ MemFs::Dir.chdir('/test-dir')
20
+ end
21
+
22
+ it "converts a pathname to an absolute pathname" do
23
+ path = subject.absolute_path('./test-file')
24
+ expect(path).to eq('/test-dir/test-file')
25
+ end
26
+
27
+ context "when +dir_string+ is given" do
28
+ it "uses it as the starting point" do
29
+ path = subject.absolute_path('./test-file', '/no-dir')
30
+ expect(path).to eq('/no-dir/test-file')
31
+ end
32
+ end
33
+
34
+ context "when the given pathname starts with a '~'" do
35
+ it "does not expanded" do
36
+ path = subject.absolute_path('~/test-file')
37
+ expect(path).to eq('/test-dir/~/test-file')
38
+ end
39
+ end
40
+ end
41
+
17
42
  describe '.atime' do
18
43
  it "returns the last access time for the named file as a Time object" do
19
44
  expect(subject.atime('/test-file')).to be_a(Time)
@@ -34,6 +59,34 @@ module MemFs
34
59
  end
35
60
  end
36
61
 
62
+ describe ".blockdev?" do
63
+ context "when the name file exists" do
64
+ context "and it is a block device" do
65
+ it "returns true" do
66
+ fs.touch('/block-file')
67
+ file = fs.find('/block-file')
68
+ file.block_device = true
69
+ blockdev = subject.blockdev?('/block-file')
70
+ expect(blockdev).to be_true
71
+ end
72
+ end
73
+
74
+ context "and it is not a block device" do
75
+ it "returns false" do
76
+ blockdev = subject.blockdev?('/test-file')
77
+ expect(blockdev).to be_false
78
+ end
79
+ end
80
+ end
81
+
82
+ context "when the name file does not exist" do
83
+ it "returns false" do
84
+ blockdev = subject.blockdev?('/no-file')
85
+ expect(blockdev).to be_false
86
+ end
87
+ end
88
+ end
89
+
37
90
  describe ".basename" do
38
91
  it "returns the last component of the filename given in +file_name+" do
39
92
  expect(subject.basename('/path/to/file.txt')).to eq('file.txt')
@@ -48,6 +101,34 @@ module MemFs
48
101
  end
49
102
  end
50
103
 
104
+ describe ".chardev?" do
105
+ context "when the name file exists" do
106
+ context "and it is a character device" do
107
+ it "returns true" do
108
+ fs.touch('/character-file')
109
+ file = fs.find('/character-file')
110
+ file.character_device = true
111
+ chardev = subject.chardev?('/character-file')
112
+ expect(chardev).to be_true
113
+ end
114
+ end
115
+
116
+ context "and it is not a character device" do
117
+ it "returns false" do
118
+ chardev = subject.chardev?('/test-file')
119
+ expect(chardev).to be_false
120
+ end
121
+ end
122
+ end
123
+
124
+ context "when the name file does not exist" do
125
+ it "returns false" do
126
+ chardev = subject.chardev?('/no-file')
127
+ expect(chardev).to be_false
128
+ end
129
+ end
130
+ end
131
+
51
132
  describe '.chmod' do
52
133
  it "changes permission bits on the named file" do
53
134
  subject.chmod(0777, '/test-file')
@@ -131,6 +212,26 @@ module MemFs
131
212
  end
132
213
  end
133
214
 
215
+ describe ".ctime" do
216
+ it "returns the change time for the named file as a Time object" do
217
+ expect(subject.ctime('/test-file')).to be_a(Time)
218
+ end
219
+
220
+ it "raises an error if the entry does not exist" do
221
+ expect { subject.ctime('/no-file') }.to raise_error(Errno::ENOENT)
222
+ end
223
+
224
+ context "when the entry is a symlink" do
225
+ let(:time) { Time.now - 500000 }
226
+
227
+ it "returns the last access time of the last target of the link chain" do
228
+ fs.find!('/test-file').ctime = time
229
+ subject.symlink('/test-link', '/test-link2')
230
+ expect(subject.ctime('/test-link2')).to eq(time)
231
+ end
232
+ end
233
+ end
234
+
134
235
  describe ".delete" do
135
236
  it_behaves_like 'aliased method', :delete, :unlink
136
237
  end
@@ -159,6 +260,132 @@ module MemFs
159
260
  end
160
261
  end
161
262
 
263
+ describe ".executable?" do
264
+ let(:access) { 0 }
265
+ let(:gid) { 0 }
266
+ let(:uid) { 0 }
267
+
268
+ before :each do
269
+ subject.chmod(access, '/test-file')
270
+ subject.chown(uid, gid, '/test-file')
271
+ end
272
+
273
+ context "when the file is not executable by anyone" do
274
+ it "return false" do
275
+ executable = subject.executable?('/test-file')
276
+ expect(executable).to be_false
277
+ end
278
+ end
279
+
280
+ context "when the file is user executable" do
281
+ let(:access) { MemFs::Fake::Entry::UEXEC }
282
+
283
+ context "and the current user owns the file" do
284
+ before(:each) { subject.chown(uid, 0, '/test-file') }
285
+ let(:uid) { Process.euid }
286
+
287
+ it "returns true" do
288
+ executable = subject.executable?('/test-file')
289
+ expect(executable).to be_true
290
+ end
291
+ end
292
+ end
293
+
294
+ context "when the file is group executable" do
295
+ let(:access) { MemFs::Fake::Entry::GEXEC }
296
+
297
+ context "and the current user is part of the owner group" do
298
+ let(:gid) { Process.egid }
299
+
300
+ it "returns true" do
301
+ executable = subject.executable?('/test-file')
302
+ expect(executable).to be_true
303
+ end
304
+ end
305
+ end
306
+
307
+ context "when the file is executable by anyone" do
308
+ let(:access) { MemFs::Fake::Entry::OEXEC }
309
+
310
+ context "and the user has no specific right on it" do
311
+ it "returns true" do
312
+ executable = subject.executable?('/test-file')
313
+ expect(executable).to be_true
314
+ end
315
+ end
316
+ end
317
+
318
+ context "when the file does not exist" do
319
+ it "returns false" do
320
+ executable = subject.executable?('/no-file')
321
+ expect(executable).to be_false
322
+ end
323
+ end
324
+ end
325
+
326
+ describe ".executable_real?" do
327
+ let(:access) { 0 }
328
+ let(:gid) { 0 }
329
+ let(:uid) { 0 }
330
+
331
+ before :each do
332
+ subject.chmod(access, '/test-file')
333
+ subject.chown(uid, gid, '/test-file')
334
+ end
335
+
336
+ context "when the file is not executable by anyone" do
337
+ it "return false" do
338
+ executable = subject.executable_real?('/test-file')
339
+ expect(executable).to be_false
340
+ end
341
+ end
342
+
343
+ context "when the file is user executable" do
344
+ let(:access) { MemFs::Fake::Entry::UEXEC }
345
+
346
+ context "and the current user owns the file" do
347
+ before(:each) { subject.chown(uid, 0, '/test-file') }
348
+ let(:uid) { Process.uid }
349
+
350
+ it "returns true" do
351
+ executable = subject.executable_real?('/test-file')
352
+ expect(executable).to be_true
353
+ end
354
+ end
355
+ end
356
+
357
+ context "when the file is group executable" do
358
+ let(:access) { MemFs::Fake::Entry::GEXEC }
359
+
360
+ context "and the current user is part of the owner group" do
361
+ let(:gid) { Process.gid }
362
+
363
+ it "returns true" do
364
+ executable = subject.executable_real?('/test-file')
365
+ expect(executable).to be_true
366
+ end
367
+ end
368
+ end
369
+
370
+ context "when the file is executable by anyone" do
371
+ let(:access) { MemFs::Fake::Entry::OEXEC }
372
+
373
+ context "and the user has no specific right on it" do
374
+ it "returns true" do
375
+ executable = subject.executable_real?('/test-file')
376
+ expect(executable).to be_true
377
+ end
378
+ end
379
+ end
380
+
381
+ context "when the file does not exist" do
382
+ it "returns false" do
383
+ executable = subject.executable_real?('/no-file')
384
+ expect(executable).to be_false
385
+ end
386
+ end
387
+ end
388
+
162
389
  describe ".exists?" do
163
390
  it "returns true if the file exists" do
164
391
  expect(subject.exists?('/test-file')).to be_true
@@ -191,6 +418,32 @@ module MemFs
191
418
  end
192
419
  end
193
420
 
421
+ describe ".extname" do
422
+ it "returns the extension of the given path" do
423
+ expect(subject.extname('test-file.txt')).to eq('.txt')
424
+ end
425
+
426
+ context "when the given path starts with a period" do
427
+ context "and the path has no extension" do
428
+ it "returns an empty string" do
429
+ expect(subject.extname('.test-file')).to eq('')
430
+ end
431
+ end
432
+
433
+ context "and the path has an extension" do
434
+ it "returns the extension" do
435
+ expect(subject.extname('.test-file.txt')).to eq('.txt')
436
+ end
437
+ end
438
+ end
439
+
440
+ context "when the period is the last character in path" do
441
+ it "returns an empty string" do
442
+ expect(subject.extname('test-file.')).to eq('')
443
+ end
444
+ end
445
+ end
446
+
194
447
  describe ".file?" do
195
448
  context "when the named file exists" do
196
449
  context "and it is a regular file" do
@@ -213,6 +466,96 @@ module MemFs
213
466
  end
214
467
  end
215
468
 
469
+ describe ".fnmatch" do
470
+ context "when the given path matches against the given pattern" do
471
+ it "returns true" do
472
+ expect(File.fnmatch('c?t', 'cat')).to be_true
473
+ end
474
+ end
475
+
476
+ context "when the given path does not match against the given pattern" do
477
+ it "returns false" do
478
+ expect(File.fnmatch('c?t', 'tac')).to be_false
479
+ end
480
+ end
481
+ end
482
+
483
+ describe ".fnmatch?" do
484
+ it_behaves_like 'aliased method', :fnmatch?, :fnmatch
485
+ end
486
+
487
+ describe ".ftype" do
488
+ context "when the named entry is a regular file" do
489
+ it "returns 'file'" do
490
+ expect(subject.ftype('/test-file')).to eq('file')
491
+ end
492
+ end
493
+
494
+ context "when the named entry is a directory" do
495
+ it "returns 'directory'" do
496
+ expect(subject.ftype('/test-dir')).to eq('directory')
497
+ end
498
+ end
499
+
500
+ context "when the named entry is a block device" do
501
+ it "returns 'blockSpecial'" do
502
+ fs.touch('/block-file')
503
+ file = fs.find('/block-file')
504
+ file.block_device = true
505
+ expect(subject.ftype('/block-file')).to eq('blockSpecial')
506
+ end
507
+ end
508
+
509
+ context "when the named entry is a character device" do
510
+ it "returns 'characterSpecial'" do
511
+ fs.touch('/character-file')
512
+ file = fs.find('/character-file')
513
+ file.character_device = true
514
+ expect(subject.ftype('/character-file')).to eq('characterSpecial')
515
+ end
516
+ end
517
+
518
+ context "when the named entry is a symlink" do
519
+ it "returns 'link'" do
520
+ expect(subject.ftype('/test-link')).to eq('link')
521
+ end
522
+ end
523
+
524
+ # fifo and socket not handled for now
525
+
526
+ context "when the named entry has no specific type" do
527
+ it "returns 'unknown'" do
528
+ root = fs.find('/')
529
+ root.add_entry Fake::Entry.new('test-entry')
530
+ expect(subject.ftype('/test-entry')).to eq('unknown')
531
+ end
532
+ end
533
+ end
534
+
535
+ describe ".grpowned?" do
536
+ context "when the named file exists" do
537
+ context "and the effective user group owns of the file" do
538
+ it "returns true" do
539
+ subject.chown(0, Process.egid, '/test-file')
540
+ expect(File.grpowned?('/test-file')).to be_true
541
+ end
542
+ end
543
+
544
+ context "and the effective user group does not own of the file" do
545
+ it "returns false" do
546
+ subject.chown(0, 0, '/test-file')
547
+ expect(File.grpowned?('/test-file')).to be_false
548
+ end
549
+ end
550
+ end
551
+
552
+ context "when the named file does not exist" do
553
+ it "returns false" do
554
+ expect(File.grpowned?('/no-file')).to be_false
555
+ end
556
+ end
557
+ end
558
+
216
559
  describe ".identical?" do
217
560
  before :each do
218
561
  subject.open('/test-file', 'w') { |f| f.puts 'test' }
@@ -394,6 +737,30 @@ module MemFs
394
737
  end
395
738
  end
396
739
 
740
+ describe ".owned?" do
741
+ context "when the named file exists" do
742
+ context "and the effective user owns of the file" do
743
+ it "returns true" do
744
+ subject.chown(Process.euid, 0, '/test-file')
745
+ expect(File.owned?('/test-file')).to be_true
746
+ end
747
+ end
748
+
749
+ context "and the effective user does not own of the file" do
750
+ it "returns false" do
751
+ subject.chown(0, 0, '/test-file')
752
+ expect(File.owned?('/test-file')).to be_false
753
+ end
754
+ end
755
+ end
756
+
757
+ context "when the named file does not exist" do
758
+ it "returns false" do
759
+ expect(File.owned?('/no-file')).to be_false
760
+ end
761
+ end
762
+ end
763
+
397
764
  describe '.path' do
398
765
  context "when the path is a string" do
399
766
  let(:path) { '/some/path' }
@@ -412,6 +779,17 @@ module MemFs
412
779
  end
413
780
  end
414
781
 
782
+ describe ".pipe?" do
783
+ # Pipes are not handled for now
784
+
785
+ context "when the named file is not a pipe" do
786
+ it "returns false" do
787
+ pipe = File.pipe?('/test-file')
788
+ expect(pipe).to be_false
789
+ end
790
+ end
791
+ end
792
+
415
793
  describe ".read" do
416
794
  before :each do
417
795
  subject.open('/test-file', 'w') { |f| f.puts "test" }
@@ -464,65 +842,445 @@ module MemFs
464
842
  end
465
843
  end
466
844
 
467
- describe ".readlink" do
468
- it "returns the name of the file referenced by the given link" do
469
- expect(subject.readlink('/test-link')).to eq('/test-file')
470
- end
471
- end
845
+ describe ".readable?" do
846
+ let(:access) { 0 }
847
+ let(:gid) { 0 }
848
+ let(:uid) { 0 }
472
849
 
473
- describe ".rename" do
474
- it "renames the given file to the new name" do
475
- subject.rename('/test-file', '/test-file2')
476
- expect(subject.exists?('/test-file2')).to be_true
850
+ before :each do
851
+ subject.chmod(access, '/test-file')
852
+ subject.chown(uid, gid, '/test-file')
477
853
  end
478
854
 
479
- it "returns zero" do
480
- expect(subject.rename('/test-file', '/test-file2')).to eq(0)
855
+ context "when the file is not readable by anyone" do
856
+ it "return false" do
857
+ readable = subject.readable?('/test-file')
858
+ expect(readable).to be_false
859
+ end
481
860
  end
482
- end
483
861
 
484
- describe ".size" do
485
- it "returns the size of the file" do
486
- subject.open('/test-file', 'w') { |f| f.puts random_string }
487
- expect(subject.size('/test-file')).to eq(random_string.size + 1)
488
- end
489
- end
862
+ context "when the file is user readable" do
863
+ let(:access) { MemFs::Fake::Entry::UREAD }
490
864
 
491
- describe '.stat' do
492
- it "returns a File::Stat object for the named file" do
493
- expect(subject.stat('/test-file')).to be_a(File::Stat)
494
- end
865
+ context "and the current user owns the file" do
866
+ before(:each) { subject.chown(uid, 0, '/test-file') }
867
+ let(:uid) { Process.euid }
495
868
 
496
- it "follows the last symbolic link" do
497
- expect(subject.stat('/test-link').symlink?).to be_false
869
+ it "returns true" do
870
+ readable = subject.readable?('/test-file')
871
+ expect(readable).to be_true
872
+ end
873
+ end
498
874
  end
499
875
 
500
- context "when the named file does not exist" do
501
- it "raises an exception" do
502
- expect { subject.stat('/no-file') }.to raise_error(Errno::ENOENT)
876
+ context "when the file is group readable" do
877
+ let(:access) { MemFs::Fake::Entry::GREAD }
878
+
879
+ context "and the current user is part of the owner group" do
880
+ let(:gid) { Process.egid }
881
+
882
+ it "returns true" do
883
+ readable = subject.readable?('/test-file')
884
+ expect(readable).to be_true
885
+ end
503
886
  end
504
887
  end
505
888
 
506
- context "when the named file is a symlink" do
507
- context "and its target does not exist" do
508
- it "raises an exception" do
509
- expect { subject.stat('/no-link') }.to raise_error(Errno::ENOENT)
889
+ context "when the file is readable by anyone" do
890
+ let(:access) { MemFs::Fake::Entry::OREAD }
891
+
892
+ context "and the user has no specific right on it" do
893
+ it "returns true" do
894
+ readable = subject.readable?('/test-file')
895
+ expect(readable).to be_true
510
896
  end
511
897
  end
512
898
  end
513
899
 
514
- it "always returns a new object" do
515
- stat = subject.stat('/test-file')
516
- expect(subject.stat('/test-file')).not_to be(stat)
900
+ context "when the file does not exist" do
901
+ it "returns false" do
902
+ readable = subject.readable?('/no-file')
903
+ expect(readable).to be_false
904
+ end
517
905
  end
518
906
  end
519
907
 
520
- describe '.symlink' do
521
- it "creates a symbolic link named new_name" do
522
- expect(subject.symlink?('/test-link')).to be_true
908
+ describe ".readable_real?" do
909
+ let(:access) { 0 }
910
+ let(:gid) { 0 }
911
+ let(:uid) { 0 }
912
+
913
+ before :each do
914
+ subject.chmod(access, '/test-file')
915
+ subject.chown(uid, gid, '/test-file')
523
916
  end
524
917
 
525
- it "creates a symbolic link that points to an entry named old_name" do
918
+ context "when the file is not readable by anyone" do
919
+ it "return false" do
920
+ readable = subject.readable_real?('/test-file')
921
+ expect(readable).to be_false
922
+ end
923
+ end
924
+
925
+ context "when the file is user readable" do
926
+ let(:access) { MemFs::Fake::Entry::UREAD }
927
+
928
+ context "and the current user owns the file" do
929
+ before(:each) { subject.chown(uid, 0, '/test-file') }
930
+ let(:uid) { Process.uid }
931
+
932
+ it "returns true" do
933
+ readable = subject.readable_real?('/test-file')
934
+ expect(readable).to be_true
935
+ end
936
+ end
937
+ end
938
+
939
+ context "when the file is group readable" do
940
+ let(:access) { MemFs::Fake::Entry::GREAD }
941
+
942
+ context "and the current user is part of the owner group" do
943
+ let(:gid) { Process.gid }
944
+
945
+ it "returns true" do
946
+ readable = subject.readable_real?('/test-file')
947
+ expect(readable).to be_true
948
+ end
949
+ end
950
+ end
951
+
952
+ context "when the file is readable by anyone" do
953
+ let(:access) { MemFs::Fake::Entry::OREAD }
954
+
955
+ context "and the user has no specific right on it" do
956
+ it "returns true" do
957
+ readable = subject.readable_real?('/test-file')
958
+ expect(readable).to be_true
959
+ end
960
+ end
961
+ end
962
+
963
+ context "when the file does not exist" do
964
+ it "returns false" do
965
+ readable = subject.readable_real?('/no-file')
966
+ expect(readable).to be_false
967
+ end
968
+ end
969
+ end
970
+
971
+ describe ".readlink" do
972
+ it "returns the name of the file referenced by the given link" do
973
+ expect(subject.readlink('/test-link')).to eq('/test-file')
974
+ end
975
+ end
976
+
977
+ describe ".realdirpath" do
978
+ before :each do
979
+ fs.mkdir('/test-dir/sub-dir')
980
+ fs.symlink('/test-dir/sub-dir', '/test-dir/sub-dir-link')
981
+ fs.touch('/test-dir/sub-dir/test-file')
982
+ end
983
+
984
+ context "when the path does not contain any symlink or useless dots" do
985
+ it "returns the path itself" do
986
+ path = subject.realdirpath('/test-file')
987
+ expect(path).to eq('/test-file')
988
+ end
989
+ end
990
+
991
+ context "when the path contains a symlink" do
992
+ context "and the symlink is a middle part" do
993
+ it "returns the path with the symlink dereferrenced" do
994
+ path = subject.realdirpath('/test-dir/sub-dir-link/test-file')
995
+ expect(path).to eq('/test-dir/sub-dir/test-file')
996
+ end
997
+ end
998
+
999
+ context "and the symlink is the last part" do
1000
+ it "returns the path with the symlink dereferrenced" do
1001
+ path = subject.realdirpath('/test-dir/sub-dir-link')
1002
+ expect(path).to eq('/test-dir/sub-dir')
1003
+ end
1004
+ end
1005
+ end
1006
+
1007
+ context "when the path contains useless dots" do
1008
+ it "returns the path with the useless dots interpolated" do
1009
+ path = subject.realdirpath('/test-dir/../test-dir/./sub-dir/test-file')
1010
+ expect(path).to eq('/test-dir/sub-dir/test-file')
1011
+ end
1012
+ end
1013
+
1014
+ context 'when the given path is relative' do
1015
+ context "and +dir_string+ is not provided" do
1016
+ it "uses the current working directory has base directory" do
1017
+ fs.chdir('/test-dir')
1018
+ path = subject.realdirpath('../test-dir/./sub-dir/test-file')
1019
+ expect(path).to eq('/test-dir/sub-dir/test-file')
1020
+ end
1021
+ end
1022
+
1023
+ context "and +dir_string+ is provided" do
1024
+ it "uses the given directory has base directory" do
1025
+ path = subject.realdirpath('../test-dir/./sub-dir/test-file', '/test-dir')
1026
+ expect(path).to eq('/test-dir/sub-dir/test-file')
1027
+ end
1028
+ end
1029
+ end
1030
+
1031
+ context "when the last part of the given path is a symlink" do
1032
+ context "and its target does not exist" do
1033
+ before :each do
1034
+ fs.symlink('/test-dir/sub-dir/test', '/test-dir/sub-dir/test-link')
1035
+ end
1036
+
1037
+ it "uses the name of the target in the resulting path" do
1038
+ path = subject.realdirpath('/test-dir/sub-dir/test-link')
1039
+ expect(path).to eq('/test-dir/sub-dir/test')
1040
+ end
1041
+ end
1042
+ end
1043
+
1044
+ context "when the last part of the given path does not exist" do
1045
+ it "uses its name in the resulting path" do
1046
+ path = subject.realdirpath('/test-dir/sub-dir/test')
1047
+ expect(path).to eq('/test-dir/sub-dir/test')
1048
+ end
1049
+ end
1050
+
1051
+ context "when a middle part of the given path does not exist" do
1052
+ it "raises an exception" do
1053
+ expect {
1054
+ subject.realdirpath('/no-dir/test-file')
1055
+ }.to raise_error
1056
+ end
1057
+ end
1058
+ end
1059
+
1060
+ describe ".realpath" do
1061
+ before :each do
1062
+ fs.mkdir('/test-dir/sub-dir')
1063
+ fs.symlink('/test-dir/sub-dir', '/test-dir/sub-dir-link')
1064
+ fs.touch('/test-dir/sub-dir/test-file')
1065
+ end
1066
+
1067
+ context "when the path does not contain any symlink or useless dots" do
1068
+ it "returns the path itself" do
1069
+ path = subject.realpath('/test-file')
1070
+ expect(path).to eq('/test-file')
1071
+ end
1072
+ end
1073
+
1074
+ context "when the path contains a symlink" do
1075
+ context "and the symlink is a middle part" do
1076
+ it "returns the path with the symlink dereferrenced" do
1077
+ path = subject.realpath('/test-dir/sub-dir-link/test-file')
1078
+ expect(path).to eq('/test-dir/sub-dir/test-file')
1079
+ end
1080
+ end
1081
+
1082
+ context "and the symlink is the last part" do
1083
+ it "returns the path with the symlink dereferrenced" do
1084
+ path = subject.realpath('/test-dir/sub-dir-link')
1085
+ expect(path).to eq('/test-dir/sub-dir')
1086
+ end
1087
+ end
1088
+ end
1089
+
1090
+ context "when the path contains useless dots" do
1091
+ it "returns the path with the useless dots interpolated" do
1092
+ path = subject.realpath('/test-dir/../test-dir/./sub-dir/test-file')
1093
+ expect(path).to eq('/test-dir/sub-dir/test-file')
1094
+ end
1095
+ end
1096
+
1097
+ context 'when the given path is relative' do
1098
+ context "and +dir_string+ is not provided" do
1099
+ it "uses the current working directory has base directory" do
1100
+ fs.chdir('/test-dir')
1101
+ path = subject.realpath('../test-dir/./sub-dir/test-file')
1102
+ expect(path).to eq('/test-dir/sub-dir/test-file')
1103
+ end
1104
+ end
1105
+
1106
+ context "and +dir_string+ is provided" do
1107
+ it "uses the given directory has base directory" do
1108
+ path = subject.realpath('../test-dir/./sub-dir/test-file', '/test-dir')
1109
+ expect(path).to eq('/test-dir/sub-dir/test-file')
1110
+ end
1111
+ end
1112
+ end
1113
+
1114
+ context "when a part of the given path does not exist" do
1115
+ it "raises an exception" do
1116
+ expect {
1117
+ subject.realpath('/no-dir/test-file')
1118
+ }.to raise_error
1119
+ end
1120
+ end
1121
+ end
1122
+
1123
+ describe ".rename" do
1124
+ it "renames the given file to the new name" do
1125
+ subject.rename('/test-file', '/test-file2')
1126
+ expect(subject.exists?('/test-file2')).to be_true
1127
+ end
1128
+
1129
+ it "returns zero" do
1130
+ expect(subject.rename('/test-file', '/test-file2')).to eq(0)
1131
+ end
1132
+ end
1133
+
1134
+ describe ".setgid?" do
1135
+ context "when the named file exists" do
1136
+ context "and the named file has the setgid bit set" do
1137
+ it "returns true" do
1138
+ fs.chmod(02000, '/test-file')
1139
+ expect(File.setgid?('/test-file')).to be_true
1140
+ end
1141
+ end
1142
+
1143
+ context "and the named file does not have the setgid bit set" do
1144
+ it "returns false" do
1145
+ expect(File.setgid?('/test-file')).not_to be_true
1146
+ end
1147
+ end
1148
+ end
1149
+
1150
+ context "when the named file does not exist" do
1151
+ it "returns false" do
1152
+ expect(File.setgid?('/no-file')).to be_false
1153
+ end
1154
+ end
1155
+ end
1156
+
1157
+ describe ".setuid?" do
1158
+ context "when the named file exists" do
1159
+ context "and the named file has the setuid bit set" do
1160
+ it "returns true" do
1161
+ fs.chmod(04000, '/test-file')
1162
+ expect(File.setuid?('/test-file')).to be_true
1163
+ end
1164
+ end
1165
+
1166
+ context "and the named file does not have the setuid bit set" do
1167
+ it "returns false" do
1168
+ expect(File.setuid?('/test-file')).not_to be_true
1169
+ end
1170
+ end
1171
+ end
1172
+
1173
+ context "when the named file does not exist" do
1174
+ it "returns false" do
1175
+ expect(File.setuid?('/no-file')).to be_false
1176
+ end
1177
+ end
1178
+ end
1179
+
1180
+ describe ".size" do
1181
+ it "returns the size of the file" do
1182
+ subject.open('/test-file', 'w') { |f| f.puts random_string }
1183
+ expect(subject.size('/test-file')).to eq(random_string.size + 1)
1184
+ end
1185
+ end
1186
+
1187
+ describe ".size?" do
1188
+ context "when the named file exists" do
1189
+ context "and it is empty" do
1190
+ it "returns false" do
1191
+ expect(File.size?('/empty-file')).to be_false
1192
+ end
1193
+ end
1194
+
1195
+ context "and it is not empty" do
1196
+ it "returns the size of the file" do
1197
+ File.open('/content-file', 'w') { |f| f.write 'test' }
1198
+ expect(File.size?('/content-file')).to eq(4)
1199
+ end
1200
+ end
1201
+ end
1202
+
1203
+ context "when the named file does not exist" do
1204
+ it "returns false" do
1205
+ expect(File.size?('/no-file')).to be_false
1206
+ end
1207
+ end
1208
+ end
1209
+
1210
+ describe ".socket?" do
1211
+ # Sockets are not handled for now
1212
+
1213
+ context "when the named file is not a socket" do
1214
+ it "returns false" do
1215
+ socket = File.socket?('/test-file')
1216
+ expect(socket).to be_false
1217
+ end
1218
+ end
1219
+ end
1220
+
1221
+ describe '.split' do
1222
+ it "splits the given string into a directory and a file component" do
1223
+ result = subject.split('/path/to/some-file')
1224
+ expect(result).to eq(['/path/to', 'some-file'])
1225
+ end
1226
+ end
1227
+
1228
+ describe '.stat' do
1229
+ it "returns a File::Stat object for the named file" do
1230
+ expect(subject.stat('/test-file')).to be_a(File::Stat)
1231
+ end
1232
+
1233
+ it "follows the last symbolic link" do
1234
+ expect(subject.stat('/test-link').symlink?).to be_false
1235
+ end
1236
+
1237
+ context "when the named file does not exist" do
1238
+ it "raises an exception" do
1239
+ expect { subject.stat('/no-file') }.to raise_error(Errno::ENOENT)
1240
+ end
1241
+ end
1242
+
1243
+ context "when the named file is a symlink" do
1244
+ context "and its target does not exist" do
1245
+ it "raises an exception" do
1246
+ expect { subject.stat('/no-link') }.to raise_error(Errno::ENOENT)
1247
+ end
1248
+ end
1249
+ end
1250
+
1251
+ it "always returns a new object" do
1252
+ stat = subject.stat('/test-file')
1253
+ expect(subject.stat('/test-file')).not_to be(stat)
1254
+ end
1255
+ end
1256
+
1257
+ describe ".sticky?" do
1258
+ context "when the named file exists" do
1259
+ it "returns true if the named file has the sticky bit set" do
1260
+ fs.touch('/test-file')
1261
+ fs.chmod(01777, '/test-file')
1262
+ expect(File.sticky?('/test-file')).to be_true
1263
+ end
1264
+
1265
+ it "returns false if the named file hasn't' the sticky bit set" do
1266
+ fs.touch('/test-file')
1267
+ expect(File.sticky?('/test-file')).not_to be_true
1268
+ end
1269
+ end
1270
+
1271
+ context "when the named file does not exist" do
1272
+ it "returns false" do
1273
+ expect(File.sticky?('/no-file')).to be_false
1274
+ end
1275
+ end
1276
+ end
1277
+
1278
+ describe '.symlink' do
1279
+ it "creates a symbolic link named new_name" do
1280
+ expect(subject.symlink?('/test-link')).to be_true
1281
+ end
1282
+
1283
+ it "creates a symbolic link that points to an entry named old_name" do
526
1284
  expect(fs.find!('/test-link').target).to eq('/test-file')
527
1285
  end
528
1286
 
@@ -557,6 +1315,34 @@ module MemFs
557
1315
  end
558
1316
  end
559
1317
 
1318
+ describe '.truncate' do
1319
+ before :each do
1320
+ subject.open('/test-file', 'w') { |f| f.write 'x' * 50 }
1321
+ end
1322
+
1323
+ it "truncates the named file to the given size" do
1324
+ subject.truncate('/test-file', 5)
1325
+ expect(subject.size('/test-file')).to eq(5)
1326
+ end
1327
+
1328
+ it "returns zero" do
1329
+ return_value = subject.truncate('/test-file', 5)
1330
+ expect(return_value).to eq(0)
1331
+ end
1332
+
1333
+ context "when the named file does not exist" do
1334
+ it "raises an exception" do
1335
+ expect { subject.truncate('/no-file', 5) }.to raise_error
1336
+ end
1337
+ end
1338
+
1339
+ context "when the given size is negative" do
1340
+ it "it raises an exception" do
1341
+ expect { subject.truncate('/test-file', -1) }.to raise_error
1342
+ end
1343
+ end
1344
+ end
1345
+
560
1346
  describe '.umask' do
561
1347
  before :each do
562
1348
  subject.umask(0022)
@@ -626,6 +1412,209 @@ module MemFs
626
1412
  end
627
1413
  end
628
1414
 
1415
+ describe '.world_readable?' do
1416
+ before :each do
1417
+ subject.chmod(access, '/test-file')
1418
+ end
1419
+
1420
+ context 'when file_name is readable by others' do
1421
+ let(:access) { MemFs::Fake::Entry::OREAD }
1422
+
1423
+ it 'returns an integer representing the file permission bits' do
1424
+ readable = subject.world_readable?('/test-file')
1425
+ expect(readable).to eq(MemFs::Fake::Entry::OREAD)
1426
+ end
1427
+ end
1428
+
1429
+ context 'when file_name is not readable by others' do
1430
+ let(:access) { MemFs::Fake::Entry::UREAD }
1431
+
1432
+ it 'returns nil' do
1433
+ readable = subject.world_readable?('/test-file')
1434
+ expect(readable).to be_nil
1435
+ end
1436
+ end
1437
+ end
1438
+
1439
+ describe '.world_writable?' do
1440
+ before :each do
1441
+ subject.chmod(access, '/test-file')
1442
+ end
1443
+
1444
+ context 'when file_name is writable by others' do
1445
+ let(:access) { MemFs::Fake::Entry::OWRITE }
1446
+
1447
+ it 'returns an integer representing the file permission bits' do
1448
+ writable = subject.world_writable?('/test-file')
1449
+ expect(writable).to eq(MemFs::Fake::Entry::OWRITE)
1450
+ end
1451
+ end
1452
+
1453
+ context 'when file_name is not writable by others' do
1454
+ let(:access) { MemFs::Fake::Entry::UWRITE }
1455
+
1456
+ it 'returns nil' do
1457
+ writable = subject.world_writable?('/test-file')
1458
+ expect(writable).to be_nil
1459
+ end
1460
+ end
1461
+ end
1462
+
1463
+ describe ".writable?" do
1464
+ let(:access) { 0 }
1465
+ let(:gid) { 0 }
1466
+ let(:uid) { 0 }
1467
+
1468
+ before :each do
1469
+ subject.chmod(access, '/test-file')
1470
+ subject.chown(uid, gid, '/test-file')
1471
+ end
1472
+
1473
+ context "when the file is not writable by anyone" do
1474
+ it "return false" do
1475
+ writable = subject.writable?('/test-file')
1476
+ expect(writable).to be_false
1477
+ end
1478
+ end
1479
+
1480
+ context "when the file is user writable" do
1481
+ let(:access) { MemFs::Fake::Entry::UWRITE }
1482
+
1483
+ context "and the current user owns the file" do
1484
+ before(:each) { subject.chown(uid, 0, '/test-file') }
1485
+ let(:uid) { Process.euid }
1486
+
1487
+ it "returns true" do
1488
+ writable = subject.writable?('/test-file')
1489
+ expect(writable).to be_true
1490
+ end
1491
+ end
1492
+ end
1493
+
1494
+ context "when the file is group writable" do
1495
+ let(:access) { MemFs::Fake::Entry::GWRITE }
1496
+
1497
+ context "and the current user is part of the owner group" do
1498
+ let(:gid) { Process.egid }
1499
+
1500
+ it "returns true" do
1501
+ writable = subject.writable?('/test-file')
1502
+ expect(writable).to be_true
1503
+ end
1504
+ end
1505
+ end
1506
+
1507
+ context "when the file is writable by anyone" do
1508
+ let(:access) { MemFs::Fake::Entry::OWRITE }
1509
+
1510
+ context "and the user has no specific right on it" do
1511
+ it "returns true" do
1512
+ writable = subject.writable?('/test-file')
1513
+ expect(writable).to be_true
1514
+ end
1515
+ end
1516
+ end
1517
+
1518
+ context "when the file does not exist" do
1519
+ it "returns false" do
1520
+ writable = subject.writable?('/no-file')
1521
+ expect(writable).to be_false
1522
+ end
1523
+ end
1524
+ end
1525
+
1526
+ describe ".writable_real?" do
1527
+ let(:access) { 0 }
1528
+ let(:gid) { 0 }
1529
+ let(:uid) { 0 }
1530
+
1531
+ before :each do
1532
+ subject.chmod(access, '/test-file')
1533
+ subject.chown(uid, gid, '/test-file')
1534
+ end
1535
+
1536
+ context "when the file is not writable by anyone" do
1537
+ it "return false" do
1538
+ writable = subject.writable_real?('/test-file')
1539
+ expect(writable).to be_false
1540
+ end
1541
+ end
1542
+
1543
+ context "when the file is user writable" do
1544
+ let(:access) { MemFs::Fake::Entry::UWRITE }
1545
+
1546
+ context "and the current user owns the file" do
1547
+ before(:each) { subject.chown(uid, 0, '/test-file') }
1548
+ let(:uid) { Process.uid }
1549
+
1550
+ it "returns true" do
1551
+ writable = subject.writable_real?('/test-file')
1552
+ expect(writable).to be_true
1553
+ end
1554
+ end
1555
+ end
1556
+
1557
+ context "when the file is group writable" do
1558
+ let(:access) { MemFs::Fake::Entry::GWRITE }
1559
+
1560
+ context "and the current user is part of the owner group" do
1561
+ let(:gid) { Process.gid }
1562
+
1563
+ it "returns true" do
1564
+ writable = subject.writable_real?('/test-file')
1565
+ expect(writable).to be_true
1566
+ end
1567
+ end
1568
+ end
1569
+
1570
+ context "when the file is writable by anyone" do
1571
+ let(:access) { MemFs::Fake::Entry::OWRITE }
1572
+
1573
+ context "and the user has no specific right on it" do
1574
+ it "returns true" do
1575
+ writable = subject.writable_real?('/test-file')
1576
+ expect(writable).to be_true
1577
+ end
1578
+ end
1579
+ end
1580
+
1581
+ context "when the file does not exist" do
1582
+ it "returns false" do
1583
+ writable = subject.writable_real?('/no-file')
1584
+ expect(writable).to be_false
1585
+ end
1586
+ end
1587
+ end
1588
+
1589
+ describe ".zero?" do
1590
+ context "when the named file exists" do
1591
+ context "and has a zero size" do
1592
+ it "returns true" do
1593
+ zero = subject.zero?('/test-file')
1594
+ expect(zero).to be_true
1595
+ end
1596
+ end
1597
+
1598
+ context "and does not have a zero size" do
1599
+ before :each do
1600
+ File.open('/test-file', 'w') { |f| f.puts 'test' }
1601
+ end
1602
+
1603
+ it "returns false" do
1604
+ zero = subject.zero?('/test-file')
1605
+ expect(zero).to be_false
1606
+ end
1607
+ end
1608
+ end
1609
+
1610
+ context "when the named file does not exist" do
1611
+ it "returns false" do
1612
+ zero = subject.zero?('/no-file')
1613
+ expect(zero).to be_false
1614
+ end
1615
+ end
1616
+ end
1617
+
629
1618
  describe '#chmod' do
630
1619
  it "changes permission bits on the file" do
631
1620
  file.chmod(0777)
@@ -739,7 +1728,7 @@ module MemFs
739
1728
 
740
1729
  it "does not follow the last symbolic link" do
741
1730
  file = subject.new('/test-link')
742
- expect(file.lstat).to be_symlink
1731
+ expect(file.lstat.symlink?).to be_true
743
1732
  end
744
1733
 
745
1734
  context "when the named file is a symlink" do