memfs 0.5.0 → 1.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.
@@ -1,3 +1,3 @@
1
1
  module MemFs
2
- VERSION = '0.5.0'
2
+ VERSION = '1.0.0'.freeze
3
3
  end
@@ -21,11 +21,14 @@ Gem::Specification.new do |gem|
21
21
  gem.require_paths = ['lib']
22
22
 
23
23
  gem.add_development_dependency 'coveralls', '~> 0.6'
24
- gem.add_development_dependency 'rake', '~> 10.0'
24
+ gem.add_development_dependency 'rake', '~> 12.0'
25
25
  gem.add_development_dependency 'rspec', '~> 3.0'
26
26
  gem.add_development_dependency 'guard', '~> 2.6'
27
27
  gem.add_development_dependency 'guard-rspec', '~> 4.3'
28
28
  gem.add_development_dependency 'rb-inotify', '~> 0.8'
29
29
  gem.add_development_dependency 'rb-fsevent', '~> 0.9'
30
30
  gem.add_development_dependency 'rb-fchange', '~> 0.0'
31
+
32
+ listen_version = RUBY_VERSION >= '2.2.3' ? '~> 3.1' : '~> 3.0.7'
33
+ gem.add_development_dependency 'listen', listen_version
31
34
  end
@@ -2,7 +2,7 @@ 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
7
  MemFs::File.umask(0020)
8
8
  MemFs.activate!
@@ -25,12 +25,12 @@ describe FileUtils do
25
25
  end
26
26
 
27
27
  it "raises an error when the given path doesn't exist" do
28
- expect { described_class.cd('/nowhere') }.to raise_specific_error(Errno::ENOENT)
28
+ expect { described_class.cd('/nowhere') }.to raise_error(Errno::ENOENT)
29
29
  end
30
30
 
31
31
  it 'raises an error when the given path is not a directory' do
32
32
  described_class.touch('/test-file')
33
- expect { described_class.cd('/test-file') }.to raise_specific_error(Errno::ENOTDIR)
33
+ expect { described_class.cd('/test-file') }.to raise_error(Errno::ENOTDIR)
34
34
  end
35
35
 
36
36
  context 'when called with a block' do
@@ -57,7 +57,7 @@ describe FileUtils do
57
57
  end
58
58
 
59
59
  it "raises an error if the last target of the link chain doesn't exist" do
60
- expect { described_class.cd('/nowhere-link') }.to raise_specific_error(Errno::ENOENT)
60
+ expect { described_class.cd('/nowhere-link') }.to raise_error(Errno::ENOENT)
61
61
  end
62
62
  end
63
63
  end
@@ -82,7 +82,7 @@ describe FileUtils do
82
82
  end
83
83
 
84
84
  it 'raises an error if an entry does not exist' do
85
- expect { described_class.chmod(0777, '/test-file') }.to raise_specific_error(Errno::ENOENT)
85
+ expect { described_class.chmod(0777, '/test-file') }.to raise_error(Errno::ENOENT)
86
86
  end
87
87
 
88
88
  context 'when the named file is a symlink' do
@@ -296,9 +296,12 @@ describe FileUtils do
296
296
 
297
297
  context 'when +src+ does not exist' do
298
298
  it 'raises an exception' do
299
+ expected_exception =
300
+ RUBY_VERSION >= '2.4.0' ? Errno::ENOENT : RuntimeError
301
+
299
302
  expect {
300
303
  described_class.copy_entry('/test-file', '/test-copy')
301
- }.to raise_specific_error(RuntimeError)
304
+ }.to raise_error(expected_exception)
302
305
  end
303
306
  end
304
307
 
@@ -382,7 +385,7 @@ describe FileUtils do
382
385
  it 'raises an error' do
383
386
  expect {
384
387
  described_class.cp('/test-file', '/test-file')
385
- }.to raise_specific_error(ArgumentError)
388
+ }.to raise_error(ArgumentError)
386
389
  end
387
390
  end
388
391
 
@@ -400,7 +403,7 @@ describe FileUtils do
400
403
  described_class.touch(['/dest', '/test-file2'])
401
404
  expect {
402
405
  described_class.cp(['/test-file', '/test-file2'], '/dest')
403
- }.to raise_specific_error(Errno::ENOTDIR)
406
+ }.to raise_error(Errno::ENOTDIR)
404
407
  end
405
408
  end
406
409
  end
@@ -474,7 +477,7 @@ describe FileUtils do
474
477
  it 'raises an exception' do
475
478
  expect {
476
479
  described_class.install('/test-file', '/test-file')
477
- }.to raise_exception(ArgumentError)
480
+ }.to raise_error ArgumentError
478
481
  end
479
482
  end
480
483
 
@@ -527,7 +530,7 @@ describe FileUtils do
527
530
  described_class.touch('/test-file2')
528
531
  expect {
529
532
  described_class.ln('/test-file', '/test-file2')
530
- }.to raise_specific_error(SystemCallError)
533
+ }.to raise_error(SystemCallError)
531
534
  end
532
535
 
533
536
  context 'and +:force+ is set' do
@@ -552,7 +555,7 @@ describe FileUtils do
552
555
  described_class.touch(['/test-file2', '/not-a-dir'])
553
556
  expect {
554
557
  described_class.ln(['/test-file', '/test-file2'], '/not-a-dir')
555
- }.to raise_specific_error(Errno::ENOTDIR)
558
+ }.to raise_error(Errno::ENOTDIR)
556
559
  end
557
560
  end
558
561
  end
@@ -587,7 +590,7 @@ describe FileUtils do
587
590
  it 'raises an exeption' do
588
591
  expect {
589
592
  described_class.ln_s('/test-file', '/not-a-dir')
590
- }.to raise_specific_error(Errno::EEXIST)
593
+ }.to raise_error(Errno::EEXIST)
591
594
  end
592
595
 
593
596
  context 'and +:force+ is set' do
@@ -618,7 +621,7 @@ describe FileUtils do
618
621
  it 'raises an error' do
619
622
  expect {
620
623
  described_class.ln_s(['/test-file', '/test-file2'], '/not-a-dir')
621
- }.to raise_specific_error(Errno::ENOTDIR)
624
+ }.to raise_error(Errno::ENOTDIR)
622
625
  end
623
626
  end
624
627
  end
@@ -667,8 +670,6 @@ describe FileUtils do
667
670
  end
668
671
  end
669
672
  end
670
-
671
-
672
673
  end
673
674
 
674
675
  describe '.mkdir_p' do
@@ -867,7 +868,7 @@ describe FileUtils do
867
868
 
868
869
  it 'cannot remove a directory' do
869
870
  described_class.mkdir('/test-dir')
870
- expect { described_class.rm('/test-dir') }.to raise_specific_error(Errno::EPERM)
871
+ expect { described_class.rm('/test-dir') }.to raise_error(Errno::EPERM)
871
872
  end
872
873
 
873
874
  context 'when +:force+ is set' do
@@ -882,7 +883,9 @@ describe FileUtils do
882
883
 
883
884
  describe '.rm_f' do
884
885
  it 'calls rm with +:force+ set to true' do
885
- expect(described_class).to receive(:rm).with('test', force: true)
886
+ expect(described_class)
887
+ .to receive(:rm).with('test', a_hash_including(force: true))
888
+
886
889
  described_class.rm_f('test')
887
890
  end
888
891
  end
@@ -917,7 +920,9 @@ describe FileUtils do
917
920
 
918
921
  describe '.rm_rf' do
919
922
  it 'calls rm with +:force+ set to true' do
920
- expect(described_class).to receive(:rm_r).with('test', force: true)
923
+ expect(described_class)
924
+ .to receive(:rm_r).with('test', a_hash_including(force: true))
925
+
921
926
  described_class.rm_rf('test')
922
927
  end
923
928
  end
@@ -1,7 +1,7 @@
1
- require 'spec_helper'
1
+ require 'pathname'
2
2
 
3
3
  module MemFs
4
- describe Dir do
4
+ ::RSpec.describe Dir do
5
5
  subject { described_class.new('/test') }
6
6
 
7
7
  before { described_class.mkdir '/test' }
@@ -58,7 +58,6 @@ module MemFs
58
58
  before { allow(Process).to receive_messages(uid: 0) }
59
59
 
60
60
  it "changes the process's idea of the file system root" do
61
-
62
61
  described_class.mkdir('/test/subdir')
63
62
  described_class.chroot('/test')
64
63
 
@@ -146,7 +145,9 @@ module MemFs
146
145
 
147
146
  context "and the directory doesn't exist" do
148
147
  it 'raises an exception' do
149
- expect { described_class.foreach('/no-dir') {} }.to raise_error
148
+ expect {
149
+ described_class.foreach('/no-dir') {}
150
+ }.to raise_error Errno::ENOENT
150
151
  end
151
152
  end
152
153
 
@@ -154,7 +155,7 @@ module MemFs
154
155
  it 'raises an exception' do
155
156
  expect {
156
157
  described_class.foreach('/test/test-file') {}
157
- }.to raise_error
158
+ }.to raise_error Errno::ENOTDIR
158
159
  end
159
160
  end
160
161
  end
@@ -215,6 +216,8 @@ module MemFs
215
216
  it_behaves_like 'returning matching filenames', '/test?', %w[/test0 /test1 /test2]
216
217
  it_behaves_like 'returning matching filenames', '/test[01]', %w[/test0 /test1]
217
218
  it_behaves_like 'returning matching filenames', '/test[^2]', %w[/test0 /test1]
219
+ it_behaves_like 'returning matching filenames', Pathname.new('/'), %w[/]
220
+ it_behaves_like 'returning matching filenames', Pathname.new('/*'), %w[/tmp /test0 /test1 /test2]
218
221
 
219
222
  if defined?(File::FNM_EXTGLOB)
220
223
  it_behaves_like 'returning matching filenames', '/test{1,2}', %w[/test1 /test2]
@@ -308,7 +311,9 @@ module MemFs
308
311
 
309
312
  context "when the given directory doesn't exist" do
310
313
  it 'raises an exception' do
311
- expect { described_class.open('/no-dir') }.to raise_error
314
+ expect {
315
+ described_class.open('/no-dir')
316
+ }.to raise_error Errno::ENOENT
312
317
  end
313
318
  end
314
319
 
@@ -316,7 +321,9 @@ module MemFs
316
321
  before { _fs.touch('/test/test-file') }
317
322
 
318
323
  it 'raises an exception' do
319
- expect { described_class.open('/test/test-file') }.to raise_error
324
+ expect {
325
+ described_class.open('/test/test-file')
326
+ }.to raise_error Errno::ENOTDIR
320
327
  end
321
328
  end
322
329
  end
@@ -324,7 +331,9 @@ module MemFs
324
331
  describe '.new' do
325
332
  context "when the given directory doesn't exist" do
326
333
  it 'raises an exception' do
327
- expect { described_class.new('/no-dir') }.to raise_error
334
+ expect {
335
+ described_class.new('/no-dir')
336
+ }.to raise_error Errno::ENOENT
328
337
  end
329
338
  end
330
339
 
@@ -332,7 +341,9 @@ module MemFs
332
341
  before { _fs.touch('/test/test-file') }
333
342
 
334
343
  it 'raises an exception' do
335
- expect { described_class.new('/test/test-file') }.to raise_error
344
+ expect {
345
+ described_class.new('/test/test-file')
346
+ }.to raise_error Errno::ENOTDIR
336
347
  end
337
348
  end
338
349
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module MemFs
4
4
  module Fake
5
- describe Directory do
5
+ ::RSpec.describe Directory do
6
6
  subject(:directory) { described_class.new('test') }
7
7
 
8
8
  describe '.new' do
@@ -70,6 +70,10 @@ module MemFs
70
70
  it 'should remove any leading / in the path' do
71
71
  expect(directory.find('/sub_dir/file')).to be(file)
72
72
  end
73
+
74
+ it 'should remove any trailing / in the path' do
75
+ expect(directory.find('sub_dir/file/')).to be(file)
76
+ end
73
77
  end
74
78
 
75
79
  describe '#parent=' do
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module MemFs
4
4
  module Fake
5
- describe Entry do
5
+ ::RSpec.describe Entry do
6
6
  let(:entry) { described_class.new('test') }
7
7
  let(:parent) { Directory.new('parent') }
8
8
  let(:time) { Time.now - 5000 }
@@ -13,11 +13,11 @@ module MemFs
13
13
  end
14
14
 
15
15
  shared_examples 'it has accessors for' do |attribute|
16
- let(:expected) { value }
16
+ let(:expected_value) { defined?(expected) ? expected : value }
17
17
 
18
18
  it attribute do
19
19
  entry.send(:"#{attribute}=", value)
20
- expect(entry.public_send(attribute)).to eq(expected)
20
+ expect(entry.public_send(attribute)).to eq(expected_value)
21
21
  end
22
22
  end
23
23
 
@@ -125,13 +125,13 @@ module MemFs
125
125
 
126
126
  describe '#dev' do
127
127
  it 'returns an integer representing the device on which the entry resides' do
128
- expect(entry.dev).to be_a(Fixnum)
128
+ expect(entry.dev).to be_a(Integer)
129
129
  end
130
130
  end
131
131
 
132
132
  describe '#ino' do
133
133
  it 'Returns the inode number for the entry' do
134
- expect(entry.ino).to be_a(Fixnum)
134
+ expect(entry.ino).to be_a(Integer)
135
135
  end
136
136
  end
137
137
 
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
 
4
4
  module MemFs
5
5
  module Fake
6
- describe File::Content do
6
+ ::RSpec.describe File::Content do
7
7
  describe '#<<' do
8
8
  it 'writes the given string to the contained string' do
9
9
  subject << 'test'
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module MemFs
4
4
  module Fake
5
- describe File do
5
+ ::RSpec.describe File do
6
6
  let(:file) { _fs.find!('/test-file') }
7
7
 
8
8
  before do
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module MemFs
4
4
  module Fake
5
- describe Symlink do
5
+ ::RSpec.describe Symlink do
6
6
  describe '#content' do
7
7
  it "returns the target's content" do
8
8
  MemFs::File.open('/test-file', 'w') { |f| f.puts 'test' }
@@ -63,7 +63,7 @@ module MemFs
63
63
  symlink = described_class.new('/test-link', '/no-file')
64
64
  expect {
65
65
  symlink.dereferenced_path
66
- }.to raise_exception
66
+ }.to raise_error Errno::ENOENT
67
67
  end
68
68
  end
69
69
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module MemFs
4
- describe File::Stat do
4
+ ::RSpec.describe File::Stat do
5
5
  let(:file_stat) { described_class.new('/test-file') }
6
6
  let(:dereferenced_file_stat) { described_class.new('/test-file', true) }
7
7
 
@@ -131,7 +131,7 @@ module MemFs
131
131
 
132
132
  describe '#dev' do
133
133
  it 'returns an integer representing the device on which stat resides' do
134
- expect(file_stat.dev).to be_a(Fixnum)
134
+ expect(file_stat.dev).to be_a(Integer)
135
135
  end
136
136
  end
137
137
 
@@ -449,7 +449,7 @@ module MemFs
449
449
 
450
450
  describe '#ino' do
451
451
  it 'returns the inode number for stat.' do
452
- expect(file_stat.ino).to be_a(Fixnum)
452
+ expect(file_stat.ino).to be_a(Integer)
453
453
  end
454
454
  end
455
455
 
@@ -606,6 +606,7 @@ module MemFs
606
606
 
607
607
  context 'when the file does not have the setgid bit set' do
608
608
  it 'returns false' do
609
+ _fs.chmod(0644, '/test-file')
609
610
  expect(file_stat.setgid?).to be false
610
611
  end
611
612
  end
@@ -621,6 +622,7 @@ module MemFs
621
622
 
622
623
  context 'when the file does not have the setuid bit set' do
623
624
  it 'returns false' do
625
+ _fs.chmod(0644, '/test-file')
624
626
  expect(file_stat.setuid?).to be false
625
627
  end
626
628
  end
@@ -643,6 +645,7 @@ module MemFs
643
645
  end
644
646
 
645
647
  it "returns false if the named file hasn't' the sticky bit set" do
648
+ _fs.chmod(0666, '/test-file')
646
649
  expect(file_stat.sticky?).to be false
647
650
  end
648
651
  end
@@ -1,8 +1,10 @@
1
+ # encoding: UTF-8
2
+
1
3
  require 'spec_helper'
2
4
  require 'pathname'
3
5
 
4
6
  module MemFs
5
- describe File do
7
+ ::RSpec.describe File do
6
8
  subject { described_class.new('/test-file') }
7
9
  let(:write_subject) { described_class.new('/test-file', 'w') }
8
10
 
@@ -15,7 +17,6 @@ module MemFs
15
17
  described_class.symlink '/no-file', '/no-link'
16
18
  end
17
19
 
18
-
19
20
  it 'implements Enumerable' do
20
21
  expect(described_class.ancestors).to include Enumerable
21
22
  end
@@ -205,7 +206,7 @@ module MemFs
205
206
 
206
207
  it 'ignores -1 user id' do
207
208
  expect {
208
- described_class.chown -1, 42, '/test-file'
209
+ described_class.chown(-1, 42, '/test-file')
209
210
  }.to_not change { described_class.stat('/test-file').uid }
210
211
  end
211
212
 
@@ -555,21 +556,21 @@ module MemFs
555
556
 
556
557
  describe '.ftype' do
557
558
  context 'when the named entry is a regular file' do
558
- it "returns 'file'" do
559
+ it 'returns "file"' do
559
560
  ftype = described_class.ftype('/test-file')
560
561
  expect(ftype).to eq 'file'
561
562
  end
562
563
  end
563
564
 
564
565
  context 'when the named entry is a directory' do
565
- it "returns 'directory'" do
566
+ it 'returns "directory"' do
566
567
  ftype = described_class.ftype('/test-dir')
567
568
  expect(ftype).to eq 'directory'
568
569
  end
569
570
  end
570
571
 
571
572
  context 'when the named entry is a block device' do
572
- it "returns 'blockSpecial'" do
573
+ it 'returns "blockSpecial"' do
573
574
  _fs.touch '/block-file'
574
575
  file = _fs.find('/block-file')
575
576
  file.block_device = true
@@ -580,7 +581,7 @@ module MemFs
580
581
  end
581
582
 
582
583
  context 'when the named entry is a character device' do
583
- it "returns 'characterSpecial'" do
584
+ it 'returns "characterSpecial"' do
584
585
  _fs.touch '/character-file'
585
586
  file = _fs.find('/character-file')
586
587
  file.character_device = true
@@ -591,7 +592,7 @@ module MemFs
591
592
  end
592
593
 
593
594
  context 'when the named entry is a symlink' do
594
- it "returns 'link'" do
595
+ it 'returns "link"' do
595
596
  ftype = described_class.ftype('/test-link')
596
597
  expect(ftype).to eq 'link'
597
598
  end
@@ -600,7 +601,7 @@ module MemFs
600
601
  # fifo and socket not handled for now
601
602
 
602
603
  context 'when the named entry has no specific type' do
603
- it "returns 'unknown'" do
604
+ it 'returns "unknown"' do
604
605
  root = _fs.find '/'
605
606
  root.add_entry Fake::Entry.new('test-entry')
606
607
 
@@ -727,7 +728,7 @@ module MemFs
727
728
  expect(mode).to be 0100777
728
729
  end
729
730
 
730
- it "does not change permission bits on the link's target" do
731
+ it 'does not change permission bits on the links target' do
731
732
  old_mode = described_class.stat('/test-file').mode
732
733
  described_class.lchmod 0777, '/test-link'
733
734
 
@@ -791,18 +792,45 @@ module MemFs
791
792
  is_symlink = described_class.lstat('/test-link').symlink?
792
793
  expect(is_symlink).to be true
793
794
  end
795
+ end
796
+ end
794
797
 
795
- context 'and its target does not exist' do
796
- it 'ignores errors' do
798
+ describe '.new' do
799
+ it 'resets the file position to the beginning' do
800
+ described_class.open('/test-file', 'w') { |f| f.write 'hello' }
801
+
802
+ contents = described_class.open('/test-file', 'r', &:read)
803
+ expect(contents).to eq('hello')
804
+
805
+ contents = described_class.open('/test-file', 'r', &:read)
806
+ expect(contents).to eq('hello')
807
+ end
808
+
809
+ context 'when only the filename is provided' do
810
+ context 'and the file exists' do
811
+ it 'returns the open file' do
812
+ file = described_class.new('/test-file')
813
+ expect(file).to be_a(MemFs::File)
814
+ end
815
+ end
816
+
817
+ context 'and the file does not exist' do
818
+ it 'raises an exception' do
819
+ expect {
820
+ described_class.new('missing-file')
821
+ }.to raise_error(Errno::ENOENT)
822
+ end
823
+ end
824
+
825
+ context 'when the file is a symlink and its target does not exist' do
826
+ it 'raises an exception' do
797
827
  expect {
798
- described_class.lstat('/no-link')
799
- }.not_to raise_error
828
+ described_class.new('/no-link')
829
+ }.to raise_error(Errno::ENOENT)
800
830
  end
801
831
  end
802
832
  end
803
- end
804
833
 
805
- describe '.new' do
806
834
  context 'when the mode is provided' do
807
835
  context 'and it is an integer' do
808
836
  subject { described_class.new('/test-file', File::RDWR) }
@@ -820,7 +848,8 @@ module MemFs
820
848
 
821
849
  it 'sets the write+create+truncate mode for "w"' do
822
850
  subject = described_class.new('/test-file', 'w')
823
- expect(subject.send(:opening_mode)).to eq File::CREAT|File::TRUNC|File::WRONLY
851
+ expect(subject.send(:opening_mode)).to \
852
+ eq File::CREAT | File::TRUNC | File::WRONLY
824
853
  end
825
854
 
826
855
  it 'sets the read+write mode for "r+"' do
@@ -830,17 +859,20 @@ module MemFs
830
859
 
831
860
  it 'sets the read+write+create+truncate mode for "w+"' do
832
861
  subject = described_class.new('/test-file', 'w+')
833
- expect(subject.send(:opening_mode)).to eq File::CREAT|File::TRUNC|File::RDWR
862
+ expect(subject.send(:opening_mode)).to \
863
+ eq File::CREAT | File::TRUNC | File::RDWR
834
864
  end
835
865
 
836
866
  it 'sets the write+create+append mode for "a"' do
837
867
  subject = described_class.new('/test-file', 'a')
838
- expect(subject.send(:opening_mode)).to eq File::CREAT|File::APPEND|File::WRONLY
868
+ expect(subject.send(:opening_mode)).to \
869
+ eq File::CREAT | File::APPEND | File::WRONLY
839
870
  end
840
871
 
841
872
  it 'sets the read+write+create+append mode for "a+"' do
842
873
  subject = described_class.new('/test-file', 'a+')
843
- expect(subject.send(:opening_mode)).to eq File::CREAT|File::APPEND|File::RDWR
874
+ expect(subject.send(:opening_mode)).to \
875
+ eq File::CREAT | File::APPEND | File::RDWR
844
876
  end
845
877
 
846
878
  it 'handles the :bom option' do
@@ -889,7 +921,9 @@ module MemFs
889
921
 
890
922
  context 'when too many arguments are given' do
891
923
  it 'raises an exception' do
892
- expect { described_class.new(1, 2, 3, 4) }.to raise_error(ArgumentError)
924
+ expect {
925
+ described_class.new(1, 2, 3, 4)
926
+ }.to raise_error(ArgumentError)
893
927
  end
894
928
  end
895
929
  end
@@ -989,18 +1023,18 @@ module MemFs
989
1023
 
990
1024
  context 'when the last argument is a hash' do
991
1025
  it 'passes the contained options to +open+' do
992
- expect(described_class).to receive(:open)
993
- .with('/test-file', File::RDONLY, encoding: 'UTF-8')
994
- .and_return(subject)
1026
+ expect(described_class).to \
1027
+ receive(:open)
1028
+ .with('/test-file', File::RDONLY, encoding: 'UTF-8')
1029
+ .and_return(subject)
995
1030
 
996
1031
  described_class.read '/test-file', encoding: 'UTF-8'
997
1032
  end
998
1033
 
999
1034
  context 'when it contains the +open_args+ key' do
1000
1035
  it 'takes precedence over the other options' do
1001
- expect(described_class).to receive(:open)
1002
- .with('/test-file', 'r')
1003
- .and_return(subject)
1036
+ expect(described_class).to \
1037
+ receive(:open).with('/test-file', 'r').and_return(subject)
1004
1038
 
1005
1039
  described_class.read '/test-file', mode: 'w', open_args: ['r']
1006
1040
  end
@@ -1220,7 +1254,7 @@ module MemFs
1220
1254
  it 'raises an exception' do
1221
1255
  expect {
1222
1256
  described_class.realdirpath '/no-dir/test-file'
1223
- }.to raise_error
1257
+ }.to raise_error Errno::ENOENT
1224
1258
  end
1225
1259
  end
1226
1260
  end
@@ -1284,7 +1318,7 @@ module MemFs
1284
1318
  it 'raises an exception' do
1285
1319
  expect {
1286
1320
  described_class.realpath '/no-dir/test-file'
1287
- }.to raise_error
1321
+ }.to raise_error Errno::ENOENT
1288
1322
  end
1289
1323
  end
1290
1324
  end
@@ -1316,6 +1350,8 @@ module MemFs
1316
1350
 
1317
1351
  context 'and the named file does not have the setgid bit set' do
1318
1352
  it 'returns false' do
1353
+ _fs.chmod 0644, '/test-file'
1354
+
1319
1355
  setgid = File.setgid?('/test-file')
1320
1356
  expect(setgid).not_to be true
1321
1357
  end
@@ -1343,6 +1379,8 @@ module MemFs
1343
1379
 
1344
1380
  context 'and the named file does not have the setuid bit set' do
1345
1381
  it 'returns false' do
1382
+ _fs.chmod 0644, '/test-file'
1383
+
1346
1384
  setuid = File.setuid?('/test-file')
1347
1385
  expect(setuid).not_to be true
1348
1386
  end
@@ -1441,10 +1479,10 @@ module MemFs
1441
1479
  end
1442
1480
 
1443
1481
  it 'always returns a new object' do
1444
- stat_1 = described_class.stat('/test-file')
1445
- stat_2 = described_class.stat('/test-file')
1482
+ stat1 = described_class.stat('/test-file')
1483
+ stat2 = described_class.stat('/test-file')
1446
1484
 
1447
- expect(stat_2).not_to be stat_1
1485
+ expect(stat2).not_to be stat1
1448
1486
  end
1449
1487
  end
1450
1488
 
@@ -1458,8 +1496,9 @@ module MemFs
1458
1496
  expect(sticky).to be true
1459
1497
  end
1460
1498
 
1461
- it "returns false if the named file hasn't' the sticky bit set" do
1499
+ it 'returns false if the named file hasnt the sticky bit set' do
1462
1500
  _fs.touch '/test-file'
1501
+ _fs.chmod 0666, '/test-file'
1463
1502
 
1464
1503
  sticky = File.sticky?('/test-file')
1465
1504
  expect(sticky).to be false
@@ -1540,13 +1579,17 @@ module MemFs
1540
1579
 
1541
1580
  context 'when the named file does not exist' do
1542
1581
  it 'raises an exception' do
1543
- expect { described_class.truncate '/no-file', 5 }.to raise_error
1582
+ expect {
1583
+ described_class.truncate '/no-file', 5
1584
+ }.to raise_error Errno::ENOENT
1544
1585
  end
1545
1586
  end
1546
1587
 
1547
1588
  context 'when the given size is negative' do
1548
1589
  it 'it raises an exception' do
1549
- expect { described_class.truncate '/test-file', -1 }.to raise_error
1590
+ expect {
1591
+ described_class.truncate '/test-file', -1
1592
+ }.to raise_error TypeError
1550
1593
  end
1551
1594
  end
1552
1595
  end
@@ -1803,6 +1846,54 @@ module MemFs
1803
1846
  end
1804
1847
  end
1805
1848
 
1849
+ describe '.write' do
1850
+ it 'writes the string to the given file' do
1851
+ described_class.write('/test-file', 'test')
1852
+ read_content = described_class.read('/test-file')
1853
+ expect(read_content).to eq 'test'
1854
+ end
1855
+
1856
+ context 'when +offset+ is provided' do
1857
+ it 'writes the string to the given file when offset is 0' do
1858
+ described_class.write('/test-file', 'test', 0)
1859
+ read_content = described_class.read('/test-file')
1860
+ expect(read_content).to eq 'test'
1861
+ end
1862
+
1863
+ it 'writes the string to the given file when offset is nil' do
1864
+ described_class.write('/test-file', 'test', nil)
1865
+ read_content = described_class.read('/test-file')
1866
+ expect(read_content).to eq 'test'
1867
+ end
1868
+
1869
+ it 'starts writing from the offset' do
1870
+ skip('Offsets not yet implemented in IO.write')
1871
+ described_class.write('/test-file', 'test')
1872
+ described_class.write('/test-file', 'test', 2)
1873
+ read_content = described_class.read('/test-file')
1874
+ expect(read_content).to eq 'tetest'
1875
+ end
1876
+
1877
+ it 'raises an error if offset is negative' do
1878
+ expect {
1879
+ described_class.write('/test-file', 'foo', -1)
1880
+ }.to raise_error Errno::EINVAL
1881
+ end
1882
+
1883
+ it 'raises an error if offset is a boolean' do
1884
+ expect {
1885
+ described_class.write '/test-file', 'foo', false
1886
+ }.to raise_error TypeError
1887
+ end
1888
+
1889
+ it 'raises an error if offset is a string' do
1890
+ expect {
1891
+ described_class.write '/test-file', 'foo', 'offset'
1892
+ }.to raise_error TypeError
1893
+ end
1894
+ end
1895
+ end
1896
+
1806
1897
  describe '.zero?' do
1807
1898
  context 'when the named file exists' do
1808
1899
  context 'and has a zero size' do
@@ -1906,7 +1997,7 @@ module MemFs
1906
1997
  end
1907
1998
 
1908
1999
  describe '#autoclose?' do
1909
- it "returns true by default" do
2000
+ it 'returns true by default' do
1910
2001
  expect(subject.autoclose?).to be true
1911
2002
  end
1912
2003
 
@@ -1938,7 +2029,7 @@ module MemFs
1938
2029
  expect(subject.binmode?).to be true
1939
2030
  end
1940
2031
 
1941
- it "sets the file encoding to ASCII-8BIT" do
2032
+ it 'sets the file encoding to ASCII-8BIT' do
1942
2033
  subject.binmode
1943
2034
 
1944
2035
  encoding = subject.external_encoding
@@ -1947,7 +2038,7 @@ module MemFs
1947
2038
  end
1948
2039
 
1949
2040
  describe '#binmode?' do
1950
- it "returns false by default" do
2041
+ it 'returns false by default' do
1951
2042
  expect(subject.binmode?).to be false
1952
2043
  end
1953
2044
 
@@ -2023,7 +2114,7 @@ module MemFs
2023
2114
 
2024
2115
  it 'ignores -1 user id' do
2025
2116
  expect {
2026
- subject.chown -1, 42
2117
+ subject.chown(-1, 42)
2027
2118
  }.to_not change { subject.stat.uid }
2028
2119
  end
2029
2120
 
@@ -2097,7 +2188,7 @@ module MemFs
2097
2188
  expect(subject.close_on_exec?).to be true
2098
2189
  end
2099
2190
 
2100
- context "when the close-on-exec flag is set to false" do
2191
+ context 'when the close-on-exec flag is set to false' do
2101
2192
  before { subject.close_on_exec = false }
2102
2193
 
2103
2194
  it 'returns false' do
@@ -2186,7 +2277,7 @@ module MemFs
2186
2277
  context 'when the file is not open for reading' do
2187
2278
  it 'raises an exception' do
2188
2279
  expect {
2189
- write_subject.each_byte { |b| }
2280
+ write_subject.each_byte {}
2190
2281
  }.to raise_error IOError
2191
2282
  end
2192
2283
 
@@ -2223,7 +2314,7 @@ module MemFs
2223
2314
  context 'when the file is not open for reading' do
2224
2315
  it 'raises an exception' do
2225
2316
  expect {
2226
- write_subject.each_char { |b| }
2317
+ write_subject.each_char {}
2227
2318
  }.to raise_error IOError
2228
2319
  end
2229
2320
 
@@ -2325,19 +2416,11 @@ module MemFs
2325
2416
  expect(subject.lstat).to be_a File::Stat
2326
2417
  end
2327
2418
 
2328
- it 'does not follow the last symbolic link' do
2329
- file = described_class.new('/test-link')
2419
+ context 'when the given file is a symlink' do
2420
+ subject { described_class.new('/test-link') }
2330
2421
 
2331
- is_symlink = file.lstat.symlink?
2332
- expect(is_symlink).to be true
2333
- end
2334
-
2335
- context 'when the named file is a symlink' do
2336
- context 'and its target does not exist' do
2337
- it 'ignores errors' do
2338
- file = described_class.new('/no-link')
2339
- expect { file.lstat }.not_to raise_error
2340
- end
2422
+ it 'does not follow the last symbolic link' do
2423
+ expect(subject.lstat).to be_symlink
2341
2424
  end
2342
2425
  end
2343
2426
  end
@@ -2507,7 +2590,7 @@ module MemFs
2507
2590
  expect(content).to eq "test\n"
2508
2591
  end
2509
2592
 
2510
- it "does not override the file's content" do
2593
+ it 'does not override the files content' do
2511
2594
  write_subject.puts 'test'
2512
2595
  write_subject.puts 'test'
2513
2596
  write_subject.close
@@ -2599,7 +2682,7 @@ module MemFs
2599
2682
 
2600
2683
  context 'when +whence+ is IO::SEEK_END' do
2601
2684
  it 'seeks to +amount+ plus end of stream' do
2602
- subject.seek -1, ::IO::SEEK_END
2685
+ subject.seek(-1, ::IO::SEEK_END)
2603
2686
 
2604
2687
  expect(subject.pos).to be 4
2605
2688
  end
@@ -2621,7 +2704,7 @@ module MemFs
2621
2704
 
2622
2705
  context 'if the position ends up to be less than zero' do
2623
2706
  it 'raises an exception' do
2624
- expect { subject.seek -1 }.to raise_error Errno::EINVAL
2707
+ expect { subject.seek(-1) }.to raise_error Errno::EINVAL
2625
2708
  end
2626
2709
  end
2627
2710
  end