fakefs 2.6.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/fakefs/base.rb +2 -0
- data/lib/fakefs/dir.rb +7 -3
- data/lib/fakefs/fake/dir.rb +2 -0
- data/lib/fakefs/fake/file.rb +3 -4
- data/lib/fakefs/fake/inode.rb +5 -7
- data/lib/fakefs/fake/symlink.rb +3 -1
- data/lib/fakefs/file.rb +241 -63
- data/lib/fakefs/file_system.rb +2 -0
- data/lib/fakefs/file_test.rb +2 -0
- data/lib/fakefs/fileutils.rb +2 -0
- data/lib/fakefs/flockable_file.rb +11 -5
- data/lib/fakefs/globber.rb +8 -6
- data/lib/fakefs/io.rb +2 -0
- data/lib/fakefs/irb.rb +2 -0
- data/lib/fakefs/kernel.rb +3 -1
- data/lib/fakefs/pathname.rb +6 -3
- data/lib/fakefs/pry.rb +2 -0
- data/lib/fakefs/safe.rb +2 -0
- data/lib/fakefs/spec_helpers.rb +2 -0
- data/lib/fakefs/version.rb +3 -1
- data/lib/fakefs.rb +2 -0
- metadata +48 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5e3224ff5a1d920e4564617bcb22fa5a7ece1e956cd8d4ea5602f3486780ac2f
|
|
4
|
+
data.tar.gz: 66ee5d6658990778978ed1531c115ae28ad08414cf9aa1bc90f6fd7e6400b22f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 42daab712ce7b73ca3ffef7b383834eac7e624bdbf43e4098000fdca7d16cc92d505a5631e256248734962d8db7cb148842d4efc1853686f9cbe5d8b288c6c89
|
|
7
|
+
data.tar.gz: 5514fc676ba615bd6387ad44cc3fa447fc566e265178729d8bb30a4098834e11a9f562f6cc8f25cc88b2c9d386827cc67506b46226008241510c67edbbeb6f81
|
data/lib/fakefs/base.rb
CHANGED
data/lib/fakefs/dir.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'English'
|
|
2
4
|
|
|
3
5
|
module FakeFS
|
|
@@ -127,10 +129,10 @@ module FakeFS
|
|
|
127
129
|
end
|
|
128
130
|
end
|
|
129
131
|
|
|
130
|
-
def self.glob(pattern, _flags = 0, flags: _flags, base: nil, &block) # rubocop:disable Lint/UnderscorePrefixedVariableName
|
|
132
|
+
def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true, &block) # rubocop:disable Lint/UnderscorePrefixedVariableName
|
|
131
133
|
pwd = FileSystem.normalize_path(base || Dir.pwd)
|
|
132
134
|
matches_for_pattern = lambda do |matcher|
|
|
133
|
-
[FileSystem.find_with_glob(matcher, flags, true, dir: pwd) || []].flatten.map do |e|
|
|
135
|
+
matched = [FileSystem.find_with_glob(matcher, flags, true, dir: pwd) || []].flatten.map do |e|
|
|
134
136
|
pwd_regex = %r{\A#{pwd.gsub('+') { '\+' }}/?}
|
|
135
137
|
if pwd.match(%r{\A/?\z}) ||
|
|
136
138
|
!e.to_s.match(pwd_regex)
|
|
@@ -138,7 +140,9 @@ module FakeFS
|
|
|
138
140
|
else
|
|
139
141
|
e.to_s.match(pwd_regex).post_match
|
|
140
142
|
end
|
|
141
|
-
end
|
|
143
|
+
end
|
|
144
|
+
matched.sort! if sort
|
|
145
|
+
matched
|
|
142
146
|
end
|
|
143
147
|
|
|
144
148
|
files =
|
data/lib/fakefs/fake/dir.rb
CHANGED
data/lib/fakefs/fake/file.rb
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module FakeFS
|
|
2
4
|
# Fake file class
|
|
3
5
|
class FakeFile
|
|
4
|
-
attr_accessor :name, :parent, :mtime, :atime, :mode, :uid, :gid
|
|
5
|
-
attr_reader :ctime, :birthtime
|
|
6
|
+
attr_accessor :name, :parent, :mtime, :atime, :mode, :uid, :gid, :ctime, :birthtime, :inode
|
|
6
7
|
|
|
7
8
|
def initialize(name = nil, parent = nil)
|
|
8
9
|
@name = name
|
|
@@ -17,8 +18,6 @@ module FakeFS
|
|
|
17
18
|
@gid = Process.gid
|
|
18
19
|
end
|
|
19
20
|
|
|
20
|
-
attr_accessor :inode
|
|
21
|
-
|
|
22
21
|
def content
|
|
23
22
|
@inode.content
|
|
24
23
|
end
|
data/lib/fakefs/fake/inode.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module FakeFS
|
|
2
4
|
# Inode class
|
|
3
5
|
class FakeInode
|
|
@@ -10,14 +12,11 @@ module FakeFS
|
|
|
10
12
|
assign_inode_num
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
attr_accessor :content
|
|
14
|
-
attr_accessor :links
|
|
15
|
-
attr_accessor :inode_num
|
|
15
|
+
attr_accessor :content, :links, :inode_num
|
|
16
16
|
|
|
17
17
|
# please see: http://iacobson.net/beware-of-ruby-class-variables/
|
|
18
18
|
class << self
|
|
19
|
-
attr_accessor :freed_inodes
|
|
20
|
-
attr_accessor :next_inode_num
|
|
19
|
+
attr_accessor :freed_inodes, :next_inode_num
|
|
21
20
|
|
|
22
21
|
# This method should only be used for tests
|
|
23
22
|
# When called, it will reset the current inode information of the FakeFS
|
|
@@ -28,8 +27,7 @@ module FakeFS
|
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
def assign_inode_num
|
|
31
|
-
|
|
32
|
-
else
|
|
30
|
+
unless (@inode_num = self.class.freed_inodes.shift)
|
|
33
31
|
@inode_num = self.class.next_inode_num
|
|
34
32
|
self.class.next_inode_num += 1
|
|
35
33
|
end
|
data/lib/fakefs/fake/symlink.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module FakeFS
|
|
2
4
|
# Fake symlink class
|
|
3
5
|
class FakeSymlink
|
|
@@ -29,7 +31,7 @@ module FakeFS
|
|
|
29
31
|
|
|
30
32
|
private
|
|
31
33
|
|
|
32
|
-
def method_missing(*args, &block)
|
|
34
|
+
def method_missing(*args, &block)
|
|
33
35
|
entry.send(*args, &block)
|
|
34
36
|
end
|
|
35
37
|
end
|
data/lib/fakefs/file.rb
CHANGED
|
@@ -1,19 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'stringio'
|
|
2
4
|
|
|
3
5
|
module FakeFS
|
|
4
6
|
# FakeFS File class inherit StringIO
|
|
5
7
|
class File < StringIO
|
|
6
8
|
MODES = [
|
|
7
|
-
READ_ONLY = 'r'
|
|
8
|
-
READ_WRITE = 'r+'
|
|
9
|
-
WRITE_ONLY = 'w'
|
|
10
|
-
READ_WRITE_TRUNCATE = 'w+'
|
|
11
|
-
APPEND_WRITE_ONLY = 'a'
|
|
12
|
-
APPEND_READ_WRITE = 'a+'
|
|
9
|
+
READ_ONLY = 'r',
|
|
10
|
+
READ_WRITE = 'r+',
|
|
11
|
+
WRITE_ONLY = 'w',
|
|
12
|
+
READ_WRITE_TRUNCATE = 'w+',
|
|
13
|
+
APPEND_WRITE_ONLY = 'a',
|
|
14
|
+
APPEND_READ_WRITE = 'a+'
|
|
13
15
|
].freeze
|
|
14
16
|
|
|
17
|
+
FMODE_READABLE = 0x00000001
|
|
18
|
+
FMODE_WRITABLE = 0x00000002
|
|
19
|
+
FMODE_READWRITE = (FMODE_READABLE | FMODE_WRITABLE)
|
|
20
|
+
FMODE_BINMODE = 0x00000004
|
|
21
|
+
FMODE_APPEND = 0x00000040
|
|
22
|
+
FMODE_CREATE = 0x00000080
|
|
23
|
+
FMODE_EXCL = 0x00000400
|
|
24
|
+
FMODE_TRUNC = 0x00000800
|
|
25
|
+
FMODE_TEXTMODE = 0x00001000
|
|
26
|
+
|
|
27
|
+
TEXT_MODES = {
|
|
28
|
+
'r' => FMODE_READABLE,
|
|
29
|
+
'w' => FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE,
|
|
30
|
+
'a' => FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
15
33
|
FILE_CREATION_MODES = (MODES - [READ_ONLY, READ_WRITE]).freeze
|
|
34
|
+
FILE_ACCESS_MODE = (RealFile::RDONLY | RealFile::WRONLY | RealFile::RDWR)
|
|
16
35
|
|
|
36
|
+
# copied from https://github.com/ruby/ruby/blob/v2_7_8/include/ruby/io.h#L108
|
|
17
37
|
MODE_BITMASK = (
|
|
18
38
|
RealFile::RDONLY |
|
|
19
39
|
RealFile::WRONLY |
|
|
@@ -23,12 +43,11 @@ module FakeFS
|
|
|
23
43
|
RealFile::EXCL |
|
|
24
44
|
RealFile::NONBLOCK |
|
|
25
45
|
RealFile::TRUNC |
|
|
46
|
+
RealFile::BINARY |
|
|
26
47
|
(RealFile.const_defined?(:NOCTTY) ? RealFile::NOCTTY : 0) |
|
|
27
48
|
(RealFile.const_defined?(:SYNC) ? RealFile::SYNC : 0)
|
|
28
49
|
)
|
|
29
50
|
|
|
30
|
-
FILE_CREATION_BITMASK = RealFile::CREAT
|
|
31
|
-
|
|
32
51
|
def self.extname(path)
|
|
33
52
|
RealFile.extname(path)
|
|
34
53
|
end
|
|
@@ -181,6 +200,7 @@ module FakeFS
|
|
|
181
200
|
symlink.target
|
|
182
201
|
end
|
|
183
202
|
|
|
203
|
+
# TODO: support open_key_args
|
|
184
204
|
def self.read(path, *args)
|
|
185
205
|
options = args[-1].is_a?(Hash) ? args.pop : {}
|
|
186
206
|
length = args.empty? ? nil : args.shift
|
|
@@ -259,7 +279,7 @@ module FakeFS
|
|
|
259
279
|
|
|
260
280
|
def self.delete(*files)
|
|
261
281
|
files.each do |file|
|
|
262
|
-
file_name = (file.
|
|
282
|
+
file_name = (file.instance_of?(FakeFS::File) ? file.path : file.to_s)
|
|
263
283
|
raise Errno::ENOENT, file_name unless exist?(file_name)
|
|
264
284
|
|
|
265
285
|
FileUtils.rm(file_name)
|
|
@@ -344,8 +364,7 @@ module FakeFS
|
|
|
344
364
|
|
|
345
365
|
# FakeFS Stat class
|
|
346
366
|
class Stat
|
|
347
|
-
attr_reader :ctime, :mtime, :atime, :mode, :uid, :gid
|
|
348
|
-
attr_reader :birthtime
|
|
367
|
+
attr_reader :ctime, :mtime, :atime, :mode, :uid, :gid, :birthtime
|
|
349
368
|
|
|
350
369
|
def initialize(file, lstat = false)
|
|
351
370
|
raise(Errno::ENOENT, file.to_s) unless File.exist?(file)
|
|
@@ -490,17 +509,104 @@ module FakeFS
|
|
|
490
509
|
|
|
491
510
|
attr_reader :path
|
|
492
511
|
|
|
493
|
-
def initialize(path,
|
|
512
|
+
def initialize(path, *args)
|
|
513
|
+
# unable to pass args otherwise on jruby, it may cause false passes on MRI, though
|
|
514
|
+
# because explicit hash isn't supported
|
|
515
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
|
516
|
+
if args.size > 2
|
|
517
|
+
raise ArgumentError, "wrong number of arguments (given #{args.size + 1}, expected 1..3)"
|
|
518
|
+
end
|
|
519
|
+
mode, _perm = args
|
|
520
|
+
|
|
494
521
|
@path = path
|
|
495
|
-
@
|
|
496
|
-
|
|
497
|
-
|
|
522
|
+
@file = FileSystem.find(@path)
|
|
523
|
+
# real rb_scan_open_args - and rb_io_extract_modeenc - is much more complex
|
|
524
|
+
raise ArgumentError, 'mode specified twice' unless mode.nil? || opts[:mode].nil?
|
|
525
|
+
|
|
526
|
+
mode_opt = mode.nil? ? opts[:mode] : mode
|
|
527
|
+
# see vmode_handle
|
|
528
|
+
if mode_opt.nil?
|
|
529
|
+
@oflags = RealFile::RDONLY
|
|
530
|
+
elsif mode_opt.respond_to?(:to_int) && (intmode = mode_opt.to_int).instance_of?(Integer)
|
|
531
|
+
@oflags = intmode
|
|
532
|
+
else
|
|
533
|
+
unless mode_opt.is_a?(String)
|
|
534
|
+
unless mode_opt.respond_to?(:to_str)
|
|
535
|
+
raise TypeError, "no implicit conversion of #{mode_opt.class} into String"
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
strmode = mode_opt.to_str
|
|
539
|
+
unless strmode.is_a?(String)
|
|
540
|
+
raise TypeError, "can't convert #{mode_opt.class} to String " \
|
|
541
|
+
"(#{mode_opt.class}#to_str gives #{strmode.class})"
|
|
542
|
+
end
|
|
498
543
|
|
|
499
|
-
|
|
544
|
+
mode_opt = strmode
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
@oflags, @fmode = parse_strmode_oflags(mode_opt)
|
|
548
|
+
end
|
|
549
|
+
unless opts[:flags].nil?
|
|
550
|
+
if opts[:flags].is_a?(Integer)
|
|
551
|
+
@oflags |= opts[:flags]
|
|
552
|
+
elsif opts[:flags].respond_to?(:to_int)
|
|
553
|
+
intflags = opts[:flags].to_int
|
|
554
|
+
unless intflags.instance_of?(Integer)
|
|
555
|
+
raise TypeError, "can't convert #{opts[:flags].class} to Integer " \
|
|
556
|
+
"(#{opts[:flags].class}#to_int gives #{intflags.class})"
|
|
557
|
+
end
|
|
500
558
|
|
|
559
|
+
@oflags |= intflags
|
|
560
|
+
@fmode = create_fmode(@oflags)
|
|
561
|
+
else
|
|
562
|
+
raise TypeError, "no implicit conversion of #{opts[:flags].class} into Integer"
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
@fmode ||= create_fmode(@oflags)
|
|
566
|
+
@fmode = extract_binmode(opts, @fmode)
|
|
567
|
+
|
|
568
|
+
@autoclose = true
|
|
501
569
|
file_creation_mode? ? create_missing_file : check_file_existence!
|
|
570
|
+
# StringIO changes enciding of the underlying string to binary
|
|
571
|
+
# when binary data is written if it's opened in binary mode,
|
|
572
|
+
# so content might have binary encoding. StringIO also switches to
|
|
573
|
+
# binary mode if its string have binary encoding, but it might not
|
|
574
|
+
# be what we want, so insteed we use encoding parsed after super call
|
|
575
|
+
# and force set it back.
|
|
576
|
+
|
|
577
|
+
# truncate doesn't work
|
|
578
|
+
unless @file.is_a?(FakeFS::FakeDir)
|
|
579
|
+
@file.content = @file.content.dup.force_encoding(Encoding.default_external)
|
|
580
|
+
end
|
|
581
|
+
# StringIO.new 'content', nil, **{} # works in MRI, but fails in JRuby
|
|
582
|
+
# but File.open 'filename', nil, **{} is ok both in MRI and JRuby
|
|
583
|
+
|
|
584
|
+
# JRuby StringIO doesn't support kwargs without mode
|
|
585
|
+
# StringIO.new "buff", encoding: 'binary' # work on MRI, fails on JRuby
|
|
586
|
+
if RUBY_PLATFORM == "java"
|
|
587
|
+
# other opts aren't supported
|
|
588
|
+
super(@file.content, mode_opt || 'r')
|
|
589
|
+
binmode if binmode? # Looks like it doesn't care about 'b'
|
|
590
|
+
mode_opt_str = mode_opt.is_a?(String) ? mode_opt : ''
|
|
591
|
+
raise ArgumentError, 'encoding specified twice' if mode_opt_str[':'] && opts[:encoding]
|
|
592
|
+
|
|
593
|
+
# Might raise where real File just warns
|
|
594
|
+
str_encoding = mode_opt_str.split(':')[1] # internal encoding is ignored anyway
|
|
595
|
+
if opts[:encoding]
|
|
596
|
+
set_encoding(opts[:encoding])
|
|
597
|
+
elsif str_encoding && str_encoding != ''
|
|
598
|
+
set_encoding(str_encoding)
|
|
599
|
+
elsif opts[:binmode]
|
|
600
|
+
set_encoding(Encoding::BINARY)
|
|
601
|
+
end
|
|
602
|
+
else
|
|
603
|
+
super(@file.content, mode, **opts)
|
|
604
|
+
end
|
|
502
605
|
|
|
503
|
-
|
|
606
|
+
# StringIO is wrtable and readable by default, so we need to disable it
|
|
607
|
+
# but maybe it was explicitly disabled by opts
|
|
608
|
+
close_write if @fmode & FMODE_WRITABLE == 0 && !StringIO.instance_method(:closed_write?).bind(self).call
|
|
609
|
+
close_read if @fmode & FMODE_READABLE == 0 && !StringIO.instance_method(:closed_read?).bind(self).call
|
|
504
610
|
end
|
|
505
611
|
|
|
506
612
|
def exists?
|
|
@@ -622,10 +728,8 @@ module FakeFS
|
|
|
622
728
|
end
|
|
623
729
|
|
|
624
730
|
def binmode?
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
@mode.include?('binary')
|
|
628
|
-
) && !@mode.include?('bom')
|
|
731
|
+
# File.open('test_mode', mode: 'w:binary').binmode? # => false
|
|
732
|
+
@fmode & FMODE_BINMODE != 0
|
|
629
733
|
end
|
|
630
734
|
|
|
631
735
|
def close_on_exec=(_bool)
|
|
@@ -662,31 +766,34 @@ module FakeFS
|
|
|
662
766
|
|
|
663
767
|
def advise(_advice, _offset = 0, _len = 0); end
|
|
664
768
|
|
|
665
|
-
def self.write(filename, contents, offset = nil, open_args
|
|
666
|
-
offset, open_args = nil, offset if offset.is_a?(Hash)
|
|
769
|
+
def self.write(filename, contents, offset = nil, **open_args)
|
|
667
770
|
mode = offset ? 'r+' : 'w'
|
|
668
|
-
if open_args
|
|
669
|
-
|
|
670
|
-
|
|
771
|
+
if open_args[:open_args]
|
|
772
|
+
# see open_key_args
|
|
773
|
+
# todo: foreach, readlines, read also use it
|
|
774
|
+
# Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
|
|
775
|
+
open_args = open_args[:open_args]
|
|
776
|
+
if open_args.last.is_a?(Hash)
|
|
777
|
+
args = open_args[0...-1]
|
|
778
|
+
opt = open_args.last
|
|
671
779
|
else
|
|
672
|
-
|
|
673
|
-
|
|
780
|
+
args = open_args
|
|
781
|
+
opt = {}
|
|
674
782
|
end
|
|
675
783
|
else
|
|
676
|
-
args = [
|
|
784
|
+
args = [open_args.delete(:mode) || mode]
|
|
785
|
+
opt = open_args
|
|
677
786
|
end
|
|
678
787
|
if offset
|
|
679
|
-
open(*args) do |f| # rubocop:disable Security/Open
|
|
788
|
+
open(filename, *args, **opt) do |f| # rubocop:disable Security/Open
|
|
680
789
|
f.seek(offset)
|
|
681
790
|
f.write(contents)
|
|
682
791
|
end
|
|
683
792
|
else
|
|
684
|
-
open(*args) do |f| # rubocop:disable Security/Open
|
|
685
|
-
f
|
|
793
|
+
open(filename, *args, **opt) do |f| # rubocop:disable Security/Open
|
|
794
|
+
f.write(contents)
|
|
686
795
|
end
|
|
687
796
|
end
|
|
688
|
-
|
|
689
|
-
contents.length
|
|
690
797
|
end
|
|
691
798
|
|
|
692
799
|
def self.birthtime(path)
|
|
@@ -701,16 +808,6 @@ module FakeFS
|
|
|
701
808
|
self.class.birthtime(@path)
|
|
702
809
|
end
|
|
703
810
|
|
|
704
|
-
def read(length = nil, buf = '')
|
|
705
|
-
read_buf = super(length, buf)
|
|
706
|
-
if binmode?
|
|
707
|
-
read_buf&.force_encoding('ASCII-8BIT')
|
|
708
|
-
else
|
|
709
|
-
read_buf&.force_encoding(Encoding.default_external)
|
|
710
|
-
end
|
|
711
|
-
read_buf
|
|
712
|
-
end
|
|
713
|
-
|
|
714
811
|
def self.convert_symbolic_chmod_to_absolute(new_mode, current_mode)
|
|
715
812
|
# mode always must be of form <GROUP1>=<FLAGS>,<GROUP2>=<FLAGS,...
|
|
716
813
|
# e.g.: u=wr,go=x
|
|
@@ -812,9 +909,9 @@ module FakeFS
|
|
|
812
909
|
# note we multiply by 7 since the group num is 1, and octal represents digits 1-7 and we want all 3 bits
|
|
813
910
|
current_group_mode = current_file_mode & (group_num * 7)
|
|
814
911
|
if group_num == 0o100
|
|
815
|
-
current_group_mode
|
|
912
|
+
current_group_mode >>= 6
|
|
816
913
|
elsif group_num == 0o10
|
|
817
|
-
current_group_mode
|
|
914
|
+
current_group_mode >>= 3
|
|
818
915
|
end
|
|
819
916
|
|
|
820
917
|
current_group_mode
|
|
@@ -832,7 +929,7 @@ module FakeFS
|
|
|
832
929
|
elsif assignment_mode == '-'
|
|
833
930
|
current_group_mode & ~chmod_perm_num
|
|
834
931
|
else
|
|
835
|
-
raise
|
|
932
|
+
raise ArgumentError, "Unknown assignment mode #{assignment_mode}"
|
|
836
933
|
end
|
|
837
934
|
end
|
|
838
935
|
|
|
@@ -866,8 +963,95 @@ module FakeFS
|
|
|
866
963
|
|
|
867
964
|
private
|
|
868
965
|
|
|
869
|
-
def
|
|
870
|
-
|
|
966
|
+
def extract_binmode(opts, fmode)
|
|
967
|
+
textmode = opts[:textmode]
|
|
968
|
+
unless textmode.nil?
|
|
969
|
+
raise ArgumentError, "textmode specified twice" if fmode & FMODE_TEXTMODE != 0
|
|
970
|
+
raise ArgumentError, "both textmode and binmode specified" if fmode & FMODE_BINMODE != 0
|
|
971
|
+
|
|
972
|
+
# yep, false has no effect here, but still causes ArgumentError
|
|
973
|
+
fmode |= FMODE_TEXTMODE if textmode
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
binmode = opts[:binmode]
|
|
977
|
+
unless binmode.nil?
|
|
978
|
+
raise ArgumentError, "binmode specified twice" if fmode & FMODE_BINMODE != 0
|
|
979
|
+
raise ArgumentError, "both textmode and binmode specified" if fmode & FMODE_TEXTMODE != 0
|
|
980
|
+
|
|
981
|
+
fmode |= FMODE_BINMODE if binmode
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
if fmode & FMODE_BINMODE != 0 && fmode & FMODE_TEXTMODE != 0
|
|
985
|
+
raise ArgumentError, "both textmode and binmode specified"
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
fmode
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
def create_fmode(oflags)
|
|
992
|
+
# rb_io_oflags_fmode
|
|
993
|
+
fmode = 0
|
|
994
|
+
case oflags & FILE_ACCESS_MODE
|
|
995
|
+
when RealFile::RDONLY
|
|
996
|
+
fmode = FMODE_READABLE
|
|
997
|
+
when RealFile::WRONLY
|
|
998
|
+
fmode = FMODE_WRITABLE
|
|
999
|
+
when RealFile::RDWR
|
|
1000
|
+
fmode = FMODE_READWRITE
|
|
1001
|
+
end
|
|
1002
|
+
fmode |= FMODE_APPEND if (oflags & RealFile::APPEND) != 0
|
|
1003
|
+
fmode |= FMODE_TRUNC if (oflags & RealFile::TRUNC) != 0
|
|
1004
|
+
fmode |= FMODE_CREATE if (oflags & RealFile::CREAT) != 0
|
|
1005
|
+
fmode |= FMODE_EXCL if (oflags & RealFile::EXCL) != 0
|
|
1006
|
+
fmode |= FMODE_BINMODE if (oflags & RealFile::BINARY) != 0
|
|
1007
|
+
fmode
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
def parse_strmode_oflags(mode)
|
|
1011
|
+
# rb_io_modestr_fmode
|
|
1012
|
+
access_mode = mode[0]
|
|
1013
|
+
mode_modificators = mode[1..-1].split(':', 2).first
|
|
1014
|
+
fmode = TEXT_MODES[access_mode]
|
|
1015
|
+
raise ArgumentError, "invalid access mode #{mode}" unless fmode
|
|
1016
|
+
|
|
1017
|
+
mode_modificators&.each_char do |m|
|
|
1018
|
+
case m
|
|
1019
|
+
when 'b'
|
|
1020
|
+
fmode |= FMODE_BINMODE
|
|
1021
|
+
when 't'
|
|
1022
|
+
fmode |= FMODE_TEXTMODE
|
|
1023
|
+
when '+'
|
|
1024
|
+
fmode |= FMODE_READWRITE
|
|
1025
|
+
when 'x'
|
|
1026
|
+
raise ArgumentError, "invalid access mode #{mode}" unless access_mode == 'w'
|
|
1027
|
+
|
|
1028
|
+
fmode |= FMODE_EXCL
|
|
1029
|
+
else
|
|
1030
|
+
raise ArgumentError, "invalid access mode #{mode}"
|
|
1031
|
+
end
|
|
1032
|
+
end
|
|
1033
|
+
if (fmode & FMODE_BINMODE).nonzero? && (fmode & FMODE_TEXTMODE).nonzero?
|
|
1034
|
+
raise ArgumentError, "invalid access mode #{mode}"
|
|
1035
|
+
end
|
|
1036
|
+
|
|
1037
|
+
# rb_io_fmode_oflags
|
|
1038
|
+
oflags = 0
|
|
1039
|
+
case fmode & FMODE_READWRITE
|
|
1040
|
+
when FMODE_READABLE
|
|
1041
|
+
oflags |= RealFile::RDONLY
|
|
1042
|
+
when FMODE_WRITABLE
|
|
1043
|
+
oflags |= RealFile::WRONLY
|
|
1044
|
+
when FMODE_READWRITE
|
|
1045
|
+
oflags |= RealFile::RDWR
|
|
1046
|
+
end
|
|
1047
|
+
|
|
1048
|
+
oflags |= RealFile::APPEND if (fmode & FMODE_APPEND).nonzero?
|
|
1049
|
+
oflags |= RealFile::TRUNC if (fmode & FMODE_TRUNC).nonzero?
|
|
1050
|
+
oflags |= RealFile::CREAT if (fmode & FMODE_CREATE).nonzero?
|
|
1051
|
+
oflags |= RealFile::EXCL if (fmode & FMODE_EXCL).nonzero?
|
|
1052
|
+
oflags |= RealFile::BINARY if (fmode & FMODE_BINMODE).nonzero?
|
|
1053
|
+
|
|
1054
|
+
[oflags, fmode]
|
|
871
1055
|
end
|
|
872
1056
|
|
|
873
1057
|
def check_file_existence!
|
|
@@ -875,27 +1059,21 @@ module FakeFS
|
|
|
875
1059
|
end
|
|
876
1060
|
|
|
877
1061
|
def file_creation_mode?
|
|
878
|
-
mode_in?(
|
|
1062
|
+
mode_in?(RealFile::CREAT)
|
|
879
1063
|
end
|
|
880
1064
|
|
|
881
|
-
def mode_in?(
|
|
882
|
-
|
|
883
|
-
list.any? do |element|
|
|
884
|
-
@mode.include?(element)
|
|
885
|
-
end
|
|
886
|
-
end
|
|
887
|
-
end
|
|
888
|
-
|
|
889
|
-
def mode_in_bitmask?(mask)
|
|
890
|
-
(@mode & mask) != 0 if @mode.is_a?(Integer)
|
|
1065
|
+
def mode_in?(mask)
|
|
1066
|
+
(@oflags & mask) != 0
|
|
891
1067
|
end
|
|
892
1068
|
|
|
893
1069
|
# Create a missing file if the path is valid.
|
|
894
1070
|
#
|
|
895
1071
|
def create_missing_file
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1072
|
+
if @file
|
|
1073
|
+
raise Errno::EEXIST, @path.to_s if mode_in?(RealFile::EXCL)
|
|
1074
|
+
raise Errno::EISDIR, path.to_s if File.directory?(@path)
|
|
1075
|
+
return
|
|
1076
|
+
end
|
|
899
1077
|
dirname = RealFile.dirname @path
|
|
900
1078
|
|
|
901
1079
|
unless dirname == '.'
|
data/lib/fakefs/file_system.rb
CHANGED
data/lib/fakefs/file_test.rb
CHANGED
data/lib/fakefs/fileutils.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'file'
|
|
2
4
|
|
|
3
5
|
module FakeFS
|
|
@@ -27,18 +29,22 @@ module FakeFS
|
|
|
27
29
|
int_mode = mode.to_int
|
|
28
30
|
|
|
29
31
|
unless int_mode.is_a?(Integer)
|
|
30
|
-
raise TypeError, "can't convert
|
|
32
|
+
raise TypeError, "can't convert #{mode.class} to Integer (#{mode.class}#to_int gives #{int_mode.class})"
|
|
31
33
|
end
|
|
32
34
|
mode = int_mode
|
|
33
35
|
end
|
|
34
36
|
|
|
35
|
-
# real implementation may not fail on `flock 11111` -
|
|
36
|
-
#
|
|
37
|
-
#
|
|
37
|
+
# In fact, real implementation may not fail on `flock 11111` -
|
|
38
|
+
# - but fails with `f1.flock 11111111` - or may fail
|
|
39
|
+
# with another error - `f1.flock 1111111111111` gives
|
|
40
|
+
# `integer 1111111111111 too big to convert to `int' (RangeError)`
|
|
41
|
+
# - but I think it's safer to allow only documented modes.
|
|
38
42
|
unless FAKE_FS_ALLOWED_FLOCK_MODES.include?(mode)
|
|
39
43
|
# real exception
|
|
40
44
|
# Invalid argument @ rb_file_flock - filepath (Errno::EINVAL)
|
|
41
|
-
raise Errno::EINVAL.new(@path, 'rb_file_flock')
|
|
45
|
+
# raise Errno::EINVAL.new(@path, 'rb_file_flock')
|
|
46
|
+
# represents it better, but fails on JRuby
|
|
47
|
+
raise Errno::EINVAL, @path
|
|
42
48
|
end
|
|
43
49
|
0
|
|
44
50
|
end
|
data/lib/fakefs/globber.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module FakeFS
|
|
2
4
|
# Handles globbing for FakeFS.
|
|
3
5
|
module Globber
|
|
@@ -8,14 +10,14 @@ module FakeFS
|
|
|
8
10
|
|
|
9
11
|
return [pattern] if pattern[0] != '{' || pattern[-1] != '}'
|
|
10
12
|
|
|
11
|
-
part = ''
|
|
13
|
+
part = +''
|
|
12
14
|
result = []
|
|
13
15
|
|
|
14
16
|
each_char_with_levels pattern, '{', '}' do |chr, level|
|
|
15
17
|
case level
|
|
16
18
|
when 0
|
|
17
19
|
case chr
|
|
18
|
-
when '{'
|
|
20
|
+
when '{'
|
|
19
21
|
# noop
|
|
20
22
|
else
|
|
21
23
|
part << chr
|
|
@@ -24,8 +26,8 @@ module FakeFS
|
|
|
24
26
|
case chr
|
|
25
27
|
when ','
|
|
26
28
|
result << part
|
|
27
|
-
part = ''
|
|
28
|
-
when '}'
|
|
29
|
+
part = +''
|
|
30
|
+
when '}'
|
|
29
31
|
# noop
|
|
30
32
|
else
|
|
31
33
|
part << chr
|
|
@@ -43,13 +45,13 @@ module FakeFS
|
|
|
43
45
|
def path_components(pattern)
|
|
44
46
|
pattern = pattern.to_s
|
|
45
47
|
|
|
46
|
-
part = ''
|
|
48
|
+
part = +''
|
|
47
49
|
result = []
|
|
48
50
|
|
|
49
51
|
each_char_with_levels pattern, '{', '}' do |chr, level|
|
|
50
52
|
if level == 0 && chr == File::SEPARATOR
|
|
51
53
|
result << part
|
|
52
|
-
part = ''
|
|
54
|
+
part = +''
|
|
53
55
|
else
|
|
54
56
|
part << chr
|
|
55
57
|
end
|
data/lib/fakefs/io.rb
CHANGED
data/lib/fakefs/irb.rb
CHANGED
data/lib/fakefs/kernel.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module FakeFS
|
|
2
4
|
# Kernel Module
|
|
3
5
|
module Kernel
|
|
@@ -16,7 +18,7 @@ module FakeFS
|
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def self.unhijack!
|
|
19
|
-
captives[:original].
|
|
21
|
+
captives[:original].each_key do |name|
|
|
20
22
|
::Kernel.send(:remove_method, name.to_sym)
|
|
21
23
|
::Kernel.send(:define_method, name.to_sym, proc do |*args, **kwargs, &block|
|
|
22
24
|
::FakeFS::Kernel.captives[:original][name].call(*args, **kwargs, &block)
|
data/lib/fakefs/pathname.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# FakeFS module
|
|
2
4
|
module FakeFS
|
|
3
5
|
#
|
|
@@ -109,10 +111,10 @@ module FakeFS
|
|
|
109
111
|
if File::ALT_SEPARATOR
|
|
110
112
|
SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}" \
|
|
111
113
|
"#{Regexp.quote File::SEPARATOR}".freeze
|
|
112
|
-
SEPARATOR_PAT = /[#{SEPARATOR_LIST}]
|
|
114
|
+
SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
|
|
113
115
|
else
|
|
114
116
|
SEPARATOR_LIST = (Regexp.quote File::SEPARATOR).to_s.freeze
|
|
115
|
-
SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}
|
|
117
|
+
SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
|
|
116
118
|
end
|
|
117
119
|
|
|
118
120
|
# Return a pathname which the extension of the basename is substituted by
|
|
@@ -483,7 +485,8 @@ module FakeFS
|
|
|
483
485
|
while (r = chop_basename(pre))
|
|
484
486
|
pre, base = r
|
|
485
487
|
case base
|
|
486
|
-
when '.'
|
|
488
|
+
when '.'
|
|
489
|
+
# ignored
|
|
487
490
|
when '..'
|
|
488
491
|
names.unshift base
|
|
489
492
|
else
|
data/lib/fakefs/pry.rb
CHANGED
data/lib/fakefs/safe.rb
CHANGED
data/lib/fakefs/spec_helpers.rb
CHANGED
data/lib/fakefs/version.rb
CHANGED
data/lib/fakefs.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fakefs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Wanstrath
|
|
@@ -9,39 +9,66 @@ authors:
|
|
|
9
9
|
- Jeff Hodges
|
|
10
10
|
- Pat Nakajima
|
|
11
11
|
- Brian Donovan
|
|
12
|
-
autorequire:
|
|
13
12
|
bindir: bin
|
|
14
13
|
cert_chain: []
|
|
15
|
-
date:
|
|
14
|
+
date: 2025-01-20 00:00:00.000000000 Z
|
|
16
15
|
dependencies:
|
|
17
16
|
- !ruby/object:Gem::Dependency
|
|
18
17
|
name: bump
|
|
19
18
|
requirement: !ruby/object:Gem::Requirement
|
|
20
19
|
requirements:
|
|
21
|
-
- - "
|
|
20
|
+
- - ">="
|
|
22
21
|
- !ruby/object:Gem::Version
|
|
23
|
-
version: 0
|
|
22
|
+
version: '0'
|
|
24
23
|
type: :development
|
|
25
24
|
prerelease: false
|
|
26
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
27
26
|
requirements:
|
|
28
|
-
- - "
|
|
27
|
+
- - ">="
|
|
29
28
|
- !ruby/object:Gem::Version
|
|
30
|
-
version: 0
|
|
29
|
+
version: '0'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: csv
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
requirements:
|
|
34
|
+
- - ">="
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: '0'
|
|
37
|
+
type: :development
|
|
38
|
+
prerelease: false
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '0'
|
|
31
44
|
- !ruby/object:Gem::Dependency
|
|
32
45
|
name: maxitest
|
|
33
46
|
requirement: !ruby/object:Gem::Requirement
|
|
34
47
|
requirements:
|
|
35
|
-
- - "
|
|
48
|
+
- - ">="
|
|
36
49
|
- !ruby/object:Gem::Version
|
|
37
|
-
version: '
|
|
50
|
+
version: '0'
|
|
38
51
|
type: :development
|
|
39
52
|
prerelease: false
|
|
40
53
|
version_requirements: !ruby/object:Gem::Requirement
|
|
41
54
|
requirements:
|
|
42
|
-
- - "
|
|
55
|
+
- - ">="
|
|
43
56
|
- !ruby/object:Gem::Version
|
|
44
|
-
version: '
|
|
57
|
+
version: '0'
|
|
58
|
+
- !ruby/object:Gem::Dependency
|
|
59
|
+
name: mutex_m
|
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
|
61
|
+
requirements:
|
|
62
|
+
- - ">="
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
version: '0'
|
|
65
|
+
type: :development
|
|
66
|
+
prerelease: false
|
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '0'
|
|
45
72
|
- !ruby/object:Gem::Dependency
|
|
46
73
|
name: pry
|
|
47
74
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -62,42 +89,42 @@ dependencies:
|
|
|
62
89
|
requirements:
|
|
63
90
|
- - ">="
|
|
64
91
|
- !ruby/object:Gem::Version
|
|
65
|
-
version: '
|
|
92
|
+
version: '0'
|
|
66
93
|
type: :development
|
|
67
94
|
prerelease: false
|
|
68
95
|
version_requirements: !ruby/object:Gem::Requirement
|
|
69
96
|
requirements:
|
|
70
97
|
- - ">="
|
|
71
98
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: '
|
|
99
|
+
version: '0'
|
|
73
100
|
- !ruby/object:Gem::Dependency
|
|
74
101
|
name: rspec
|
|
75
102
|
requirement: !ruby/object:Gem::Requirement
|
|
76
103
|
requirements:
|
|
77
|
-
- - "
|
|
104
|
+
- - ">="
|
|
78
105
|
- !ruby/object:Gem::Version
|
|
79
|
-
version: '
|
|
106
|
+
version: '0'
|
|
80
107
|
type: :development
|
|
81
108
|
prerelease: false
|
|
82
109
|
version_requirements: !ruby/object:Gem::Requirement
|
|
83
110
|
requirements:
|
|
84
|
-
- - "
|
|
111
|
+
- - ">="
|
|
85
112
|
- !ruby/object:Gem::Version
|
|
86
|
-
version: '
|
|
113
|
+
version: '0'
|
|
87
114
|
- !ruby/object:Gem::Dependency
|
|
88
115
|
name: rubocop
|
|
89
116
|
requirement: !ruby/object:Gem::Requirement
|
|
90
117
|
requirements:
|
|
91
118
|
- - "~>"
|
|
92
119
|
- !ruby/object:Gem::Version
|
|
93
|
-
version:
|
|
120
|
+
version: 1.70.0
|
|
94
121
|
type: :development
|
|
95
122
|
prerelease: false
|
|
96
123
|
version_requirements: !ruby/object:Gem::Requirement
|
|
97
124
|
requirements:
|
|
98
125
|
- - "~>"
|
|
99
126
|
- !ruby/object:Gem::Version
|
|
100
|
-
version:
|
|
127
|
+
version: 1.70.0
|
|
101
128
|
description: A fake filesystem. Use it in your tests.
|
|
102
129
|
email:
|
|
103
130
|
- chris@ozmm.org
|
|
@@ -132,7 +159,6 @@ homepage: https://github.com/fakefs/fakefs
|
|
|
132
159
|
licenses:
|
|
133
160
|
- MIT
|
|
134
161
|
metadata: {}
|
|
135
|
-
post_install_message:
|
|
136
162
|
rdoc_options: []
|
|
137
163
|
require_paths:
|
|
138
164
|
- lib
|
|
@@ -140,15 +166,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
140
166
|
requirements:
|
|
141
167
|
- - ">="
|
|
142
168
|
- !ruby/object:Gem::Version
|
|
143
|
-
version:
|
|
169
|
+
version: 3.0.0
|
|
144
170
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
171
|
requirements:
|
|
146
172
|
- - ">="
|
|
147
173
|
- !ruby/object:Gem::Version
|
|
148
174
|
version: '0'
|
|
149
175
|
requirements: []
|
|
150
|
-
rubygems_version: 3.
|
|
151
|
-
signing_key:
|
|
176
|
+
rubygems_version: 3.6.2
|
|
152
177
|
specification_version: 4
|
|
153
178
|
summary: A fake filesystem. Use it in your tests.
|
|
154
179
|
test_files: []
|