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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +4 -0
- data/README.md +7 -1
- data/lib/memfs/dir.rb +1 -1
- data/lib/memfs/fake/directory.rb +4 -0
- data/lib/memfs/fake/entry.rb +20 -3
- data/lib/memfs/fake/file.rb +8 -0
- data/lib/memfs/fake/file/content.rb +4 -0
- data/lib/memfs/fake/symlink.rb +24 -0
- data/lib/memfs/file.rb +89 -7
- data/lib/memfs/file/stat.rb +127 -4
- data/lib/memfs/file_system.rb +0 -8
- data/lib/memfs/version.rb +1 -1
- data/spec/memfs/fake/directory_spec.rb +6 -0
- data/spec/memfs/fake/entry_spec.rb +54 -24
- data/spec/memfs/fake/file/content_spec.rb +9 -0
- data/spec/memfs/fake/file_spec.rb +22 -0
- data/spec/memfs/fake/symlink_spec.rb +70 -0
- data/spec/memfs/file/stat_spec.rb +728 -84
- data/spec/memfs/file_spec.rb +1028 -39
- data/spec/memfs/file_system_spec.rb +63 -35
- metadata +3 -5
- data/.DS_Store +0 -0
- data/lib/fileutils.rb +0 -1738
data/spec/memfs/file_spec.rb
CHANGED
@@ -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 ".
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
end
|
845
|
+
describe ".readable?" do
|
846
|
+
let(:access) { 0 }
|
847
|
+
let(:gid) { 0 }
|
848
|
+
let(:uid) { 0 }
|
472
849
|
|
473
|
-
|
474
|
-
|
475
|
-
subject.
|
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
|
-
|
480
|
-
|
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
|
-
|
485
|
-
|
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
|
-
|
492
|
-
|
493
|
-
|
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
|
-
|
497
|
-
|
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
|
501
|
-
|
502
|
-
|
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
|
507
|
-
|
508
|
-
|
509
|
-
|
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
|
-
|
515
|
-
|
516
|
-
|
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
|
521
|
-
|
522
|
-
|
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
|
-
|
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
|
1731
|
+
expect(file.lstat.symlink?).to be_true
|
743
1732
|
end
|
744
1733
|
|
745
1734
|
context "when the named file is a symlink" do
|