virtfs 0.0.1

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.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +154 -0
  8. data/Rakefile +5 -0
  9. data/lib/virtfs-nativefs-thick.rb +1 -0
  10. data/lib/virtfs-nativefs-thin.rb +1 -0
  11. data/lib/virtfs.rb +38 -0
  12. data/lib/virtfs/activation.rb +97 -0
  13. data/lib/virtfs/block_io.rb +140 -0
  14. data/lib/virtfs/byte_range.rb +71 -0
  15. data/lib/virtfs/context.rb +300 -0
  16. data/lib/virtfs/context_manager.rb +175 -0
  17. data/lib/virtfs/context_switch_class_methods.rb +96 -0
  18. data/lib/virtfs/delegate_module.rb +40 -0
  19. data/lib/virtfs/dir_instance_delegate.rb +3 -0
  20. data/lib/virtfs/exception.rb +13 -0
  21. data/lib/virtfs/file_instance_delegate.rb +3 -0
  22. data/lib/virtfs/file_modes_and_options.rb +293 -0
  23. data/lib/virtfs/find_class_methods.rb +106 -0
  24. data/lib/virtfs/io_buffer.rb +133 -0
  25. data/lib/virtfs/io_instance_delegate.rb +3 -0
  26. data/lib/virtfs/kernel.rb +146 -0
  27. data/lib/virtfs/nativefs/thick.rb +30 -0
  28. data/lib/virtfs/nativefs/thick/dir_class_methods.rb +38 -0
  29. data/lib/virtfs/nativefs/thick/file_class_methods.rb +178 -0
  30. data/lib/virtfs/nativefs/thin.rb +32 -0
  31. data/lib/virtfs/nativefs/thin/dir.rb +30 -0
  32. data/lib/virtfs/nativefs/thin/dir_class_methods.rb +41 -0
  33. data/lib/virtfs/nativefs/thin/file.rb +112 -0
  34. data/lib/virtfs/nativefs/thin/file_class_methods.rb +181 -0
  35. data/lib/virtfs/protofs/protofs.rb +7 -0
  36. data/lib/virtfs/protofs/protofs_base.rb +12 -0
  37. data/lib/virtfs/protofs/protofs_dir.rb +13 -0
  38. data/lib/virtfs/protofs/protofs_dir_class.rb +31 -0
  39. data/lib/virtfs/protofs/protofs_file.rb +27 -0
  40. data/lib/virtfs/protofs/protofs_file_class.rb +136 -0
  41. data/lib/virtfs/stat.rb +100 -0
  42. data/lib/virtfs/thin_dir_delegator.rb +79 -0
  43. data/lib/virtfs/thin_file_delegator.rb +77 -0
  44. data/lib/virtfs/thin_io_delegator_methods.rb +301 -0
  45. data/lib/virtfs/thin_io_delegator_methods_bufferio.rb +337 -0
  46. data/lib/virtfs/v_dir.rb +238 -0
  47. data/lib/virtfs/v_file.rb +480 -0
  48. data/lib/virtfs/v_io.rb +243 -0
  49. data/lib/virtfs/v_pathname.rb +128 -0
  50. data/lib/virtfs/version.rb +3 -0
  51. data/spec/activate_spec.rb +202 -0
  52. data/spec/chroot_spec.rb +120 -0
  53. data/spec/context_manager_class_spec.rb +246 -0
  54. data/spec/context_manager_instance_spec.rb +255 -0
  55. data/spec/context_spec.rb +335 -0
  56. data/spec/data/UTF-16LE-data.txt +0 -0
  57. data/spec/data/UTF-8-data.txt +212 -0
  58. data/spec/dir_class_spec.rb +506 -0
  59. data/spec/dir_instance_spec.rb +208 -0
  60. data/spec/file_class_spec.rb +2106 -0
  61. data/spec/file_instance_spec.rb +154 -0
  62. data/spec/file_modes_and_options_spec.rb +1556 -0
  63. data/spec/find_spec.rb +142 -0
  64. data/spec/io_bufferio_size_shared_examples.rb +371 -0
  65. data/spec/io_bufferio_size_spec.rb +861 -0
  66. data/spec/io_bufferio_spec.rb +801 -0
  67. data/spec/io_class_spec.rb +145 -0
  68. data/spec/io_instance_spec.rb +516 -0
  69. data/spec/kernel_spec.rb +285 -0
  70. data/spec/mount_spec.rb +186 -0
  71. data/spec/nativefs_local_root_spec.rb +132 -0
  72. data/spec/path_spec.rb +39 -0
  73. data/spec/spec_helper.rb +126 -0
  74. data/tasks/rspec.rake +3 -0
  75. data/tasks/yard.rake +7 -0
  76. data/test/UTF-8-demo.txt +212 -0
  77. data/test/bench.rb +18 -0
  78. data/test/bio_internal_test.rb +45 -0
  79. data/test/delegate_io.rb +31 -0
  80. data/test/delegate_module.rb +62 -0
  81. data/test/encode_test.rb +42 -0
  82. data/test/enoent_test.rb +30 -0
  83. data/test/namespace_test.rb +42 -0
  84. data/test/read_block_valid_encoding.rb +44 -0
  85. data/test/read_test.rb +78 -0
  86. data/test/stream_readers.rb +46 -0
  87. data/test/utf-16-demo.txt +0 -0
  88. data/test/utf8_to_utf16.rb +77 -0
  89. data/test/wrapper_test.rb +34 -0
  90. data/virtfs.gemspec +29 -0
  91. metadata +230 -0
@@ -0,0 +1,243 @@
1
+ module VirtFS
2
+ # VirtFS IO representation - implements the core Ruby IO methods, dispatching
3
+ # to underlying mounted VirtFS filesystems
4
+ #
5
+ class VIO # rubocop:disable ClassLength
6
+ include IOInstanceDelegate
7
+
8
+ VfsRealIO.constants.each { |cn| const_set(cn, VfsRealIO.const_get(cn)) }
9
+
10
+ # VFile initializer
11
+ #
12
+ # @param io_obj [VirtFS::FS::IO] handle to filesystem specific io obj
13
+ #
14
+ def initialize(io_obj)
15
+ __setobj__(io_obj)
16
+ end
17
+
18
+ #
19
+ # Some methods need to return the IO object. Methods in the delegator
20
+ # object can't do that, so we intercept them and do it here.
21
+ #
22
+
23
+ def <<(obj)
24
+ super
25
+ self
26
+ end
27
+
28
+ def binmode
29
+ super
30
+ self
31
+ end
32
+
33
+ def reopen(*args)
34
+ __setobj__(super)
35
+ self
36
+ end
37
+
38
+ def set_encoding(*args) # rubocop:disable Style/AccessorMethodName
39
+ super
40
+ self
41
+ end
42
+
43
+ def to_io
44
+ self
45
+ end
46
+
47
+ # Class methods
48
+ class << self
49
+ # Read specified number of bytes from file
50
+ #
51
+ # @param f [String] file to ready
52
+ # @param length [Integer] number of bytes to read
53
+ # @param offset [Integer] position to start reading at
54
+ #
55
+ # @return [Array<Byte>] bytes read from file (up to length size)
56
+ def binread(f, length = nil, offset = 0)
57
+ VFile.open(f, "rb") do |fobj|
58
+ fobj.pos = offset
59
+ return fobj.read unless length
60
+ return fobj.read(length)
61
+ end
62
+ end
63
+
64
+ # def binwrite()
65
+
66
+ # Copy stream from source to destination
67
+ #
68
+ # @param from [String] file stream to copy
69
+ # @param to [String] file stream to copy to
70
+ # @param max_length [Integer] max number of bytes to copy
71
+ # @param offset [Integer] position to start coying from
72
+ def copy_stream(from, to, max_length = nil, offset = 0) # rubocop:disable CyclomaticComplexity
73
+ from_file = from.is_a?(VIO) ? from : VFile.open(from, "rb")
74
+ to_file = to.is_a?(VIO) ? to : VFile.open(to, "wb") # rubocop:disable SpaceAroundOperators
75
+ return copy_from_to(from_file, to_file, max_length, offset)
76
+ ensure
77
+ from_file.close unless from_file.nil? || from.is_a?(VIO)
78
+ to_file.close unless to_file.nil? || to.is_a?(VIO) # rubocop:disable SpaceAroundOperators
79
+ end
80
+
81
+ # Invoke block for each file matching pattern
82
+ #
83
+ # IO.foreach( portname, separator=$/ <, options> ) { | line | . . . } -> nil
84
+ # IO.foreach( portname, limit <, options> ) { | line | . . . } -> nil
85
+ # IO.foreach( portname, separator, limit <, options> ) { | line | . . . } -> nil
86
+ #
87
+ def foreach(portname, *args, &block)
88
+ return VfsRealIO.foreach(portname, *args) unless filename?(portname)
89
+ return to_enum(__method__, portname, *args) unless block_given?
90
+
91
+ separator, limit, options = parse_args(args)
92
+
93
+ VFile.open(portname, "r", options) do |fobj|
94
+ fobj.each(separator, limit, &block)
95
+ end
96
+ nil
97
+ end
98
+
99
+ def pipe(*args, &block)
100
+ # XXX - should wrap VfsRealIO objects in common delegator class
101
+ # so is_a? and kind_of? will work with all IO objects.
102
+ VfsRealIO.pipe(*args, &block) # TODO: wrap returned read and write IO
103
+ end
104
+
105
+ def popen(*args, &block)
106
+ VfsRealIO.popen(*args, &block) # TODO: wrap returned IO
107
+ end
108
+
109
+ def read(portname, *args)
110
+ return VfsRealIO.read(portname, *args) unless filename?(portname)
111
+
112
+ length, offset, options = length_offset_options(args)
113
+
114
+ VFile.open(portname, "r", options) do |fobj|
115
+ fobj.pos = offset
116
+ return fobj.read unless length
117
+ return fobj.read(length)
118
+ end
119
+ end
120
+
121
+ def readlines(portname, *args)
122
+ return VfsRealIO.readlines(portname, *args) unless filename?(portname)
123
+ foreach(portname, *args).to_a
124
+ end
125
+
126
+ def select(*args)
127
+ VfsRealIO.select(*args)
128
+ end
129
+
130
+ def sysopen(*args)
131
+ VfsRealIO.sysopen(*args)
132
+ end
133
+
134
+ def try_convert(obj)
135
+ return nil unless obj.respond_to?(:to_io)
136
+ obj.to_io # TODO: wrap?
137
+ end
138
+
139
+ # Instantiate IO instance.
140
+ #
141
+ # @param integer_fd [Integer] file descriptor
142
+ # @param mode [String] mode to open IO instance
143
+ # @param hash_options options to forward to IO initialiezr
144
+ #
145
+ def new(integer_fd, mode = "r", hash_options = {})
146
+ #
147
+ # Directly instantiating an IO instance (not through File)
148
+ # will return a standard IO object.
149
+ #
150
+ fs_obj = VfsRealIO.new(integer_fd, mode, hash_options)
151
+ obj = allocate
152
+ obj.send(:initialize, fs_obj)
153
+ obj
154
+ end
155
+ alias_method :for_fd, :new
156
+
157
+ # Open IO Instance and invoke block w/ it before closing
158
+ #
159
+ # @see #new
160
+ def open(*args)
161
+ io_obj = new(*args) # IO.new or File.new
162
+ return io_obj unless block_given?
163
+ begin
164
+ return yield(io_obj)
165
+ ensure
166
+ io_obj.close
167
+ end
168
+ end
169
+
170
+ private
171
+
172
+ def filename?(portname)
173
+ portname[0] != "|"
174
+ end
175
+
176
+ # separator, limit, options
177
+ def parse_args(args)
178
+ separator = $RS
179
+ limit = nil
180
+ options = {}
181
+
182
+ while (arg = args.shift)
183
+ if arg.is_a?(String)
184
+ separator = arg
185
+ elsif arg.is_a?(Numeric)
186
+ limit = arg
187
+ elsif arg.is_a?(Hash)
188
+ options = arg
189
+ end
190
+ end
191
+ return separator, limit, options
192
+ end
193
+
194
+ def length_offset_options(args) # rubocop:disable AbcSize, PerceivedComplexity, CyclomaticComplexity
195
+ case args.length
196
+ when 0
197
+ return nil, 0, {}
198
+ when 1
199
+ return args[0].to_int, 0, {} if args[0].respond_to?(:to_int)
200
+ return nil, 0, args[0].to_hash if args[0].respond_to?(:to_hash)
201
+ int_type_error(args[0])
202
+ when 2
203
+ int_type_error(args[0]) unless args[0].respond_to?(:to_int)
204
+ return args[0].to_int, args[1].to_int, {} if args[1].respond_to?(:to_int)
205
+ return args[0].to_int, 0, args[1].to_hash if args[1].respond_to?(:to_hash)
206
+ int_type_error(args[1])
207
+ when 3
208
+ int_type_error(args[0]) unless args[0].respond_to?(:to_int)
209
+ int_type_error(args[1]) unless args[1].respond_to?(:to_int)
210
+ return args[0].to_int, args[1].to_int, args[2].to_hash if args[2].respond_to?(:to_hash)
211
+ hash_type_error(args[2])
212
+ else
213
+ raise ArgumentError, "wrong number of arguments (5+ for 1..4)"
214
+ end
215
+ end
216
+
217
+ def int_type_error(arg)
218
+ raise TypeError, "no implicit conversion from #{arg.class.name} to integer"
219
+ end
220
+
221
+ def hash_type_error(arg)
222
+ raise TypeError, "no implicit conversion from #{arg.class.name} to Hash"
223
+ end
224
+
225
+ def copy_from_to(from, to, length, offset)
226
+ chunk_size = 1024
227
+ bytes_written = 0
228
+
229
+ from.pos = offset
230
+ while (rv = from.read(chunk_size))
231
+ if length && bytes_written + rv.bytesize > length
232
+ len = length - bytes_written
233
+ to.write(rv[0, len])
234
+ break
235
+ end
236
+ to.write(rv)
237
+ bytes_written += rv.bytesize
238
+ end
239
+ bytes_written
240
+ end
241
+ end # class methods
242
+ end
243
+ end
@@ -0,0 +1,128 @@
1
+ module VirtFS
2
+ class VPathname < VfsRealPathname
3
+ def self.getwd
4
+ new(::Dir.getwd)
5
+ end
6
+
7
+ def self.pwd
8
+ getwd
9
+ end
10
+
11
+ def self.glob(*args)
12
+ return ::Dir.glob(args).collect { |p| new(p) } unless block_given?
13
+ ::Dir.glob(*args).each { |p| yield(new(p)) }
14
+ end
15
+
16
+ # absolute?
17
+ # ascend
18
+
19
+ def atime
20
+ ::File.atime(to_path)
21
+ end
22
+
23
+ # basename
24
+
25
+ def binread(*args)
26
+ ::File.binread(to_path, *args)
27
+ end
28
+
29
+ # binwrite
30
+ # birthtime
31
+ # blockdev?
32
+ # chardev?
33
+ # children
34
+ # chmod
35
+ # chown
36
+ # cleanpath
37
+ # ctime
38
+ # delete
39
+ # descend
40
+ # directory?
41
+ # dirname
42
+ # each_child
43
+ # each_entry
44
+ # each_filename
45
+ # each_line
46
+ # empty?
47
+ # entries
48
+ # eql?
49
+ # executable?
50
+ # executable_real?
51
+ # exist?
52
+
53
+ def expand_path(dirstring = nil)
54
+ return self if absolute?
55
+ self.class.new(::File.expand_path(to_path, dirstring))
56
+ end
57
+
58
+ # extname
59
+
60
+ def file?
61
+ ::File.file?(to_path)
62
+ end
63
+
64
+ # find
65
+ # fnmatch
66
+ # fnmatch?
67
+ # freeze
68
+ # ftype
69
+ # grpowned?
70
+ # join
71
+ # lchmod
72
+ # lchown
73
+ # lstat
74
+ # make_link
75
+ # make_symlink
76
+ # mkdir
77
+ # mkpath
78
+ # mountpoint?
79
+ # mtime
80
+ # open
81
+ # opendir
82
+ # owned?
83
+ # parent
84
+ # pipe?
85
+
86
+ def read(*args)
87
+ ::File.open(to_path, "r") { |f| return f.read(*args) }
88
+ end
89
+
90
+ # readable?
91
+ # readable_real?
92
+ # readlines
93
+ # readlink
94
+ # realdirpath
95
+ # realpath
96
+ # relative?
97
+ # relative_path_from
98
+ # rename
99
+ # rmdir
100
+ # rmtree
101
+ # root?
102
+ # setgid?
103
+ # setuid?
104
+ # size
105
+ # size?
106
+ # socket?
107
+ # split
108
+ # stat
109
+ # sticky?
110
+ # sub
111
+ # sub_ext
112
+ # symlink?
113
+ # sysopen
114
+ # taint
115
+ # to_path
116
+ # to_s
117
+ # truncate
118
+ # unlink
119
+ # untaint
120
+ # utime
121
+ # world_readable?
122
+ # world_writable?
123
+ # writable?
124
+ # writable_real?
125
+ # write
126
+ # zero?
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ module VirtFS
2
+ VERSION = "0.0.1" unless const_defined?(:VERSION)
3
+ end
@@ -0,0 +1,202 @@
1
+ require 'spec_helper'
2
+
3
+ describe VirtFS, " - activation (#{$fs_interface} interface)" do
4
+ before(:each) do
5
+ reset_context
6
+ @root = File::SEPARATOR
7
+ @native_fs = nativefs_class.new
8
+ VirtFS.mount(@native_fs, @root)
9
+ end
10
+
11
+ after(:each) do
12
+ VirtFS.deactivate! if VirtFS.activated?
13
+ VirtFS.umount(@root) if VirtFS.mounted?(@root)
14
+ end
15
+
16
+ it "should save reference to standard Dir class" do
17
+ expect(Object.const_defined?(:VfsRealDir)).to be true
18
+ expect(VfsRealDir).to eq(Dir)
19
+ end
20
+
21
+ it "should save reference to standard File class" do
22
+ expect(Object.const_defined?(:VfsRealFile)).to be true
23
+ expect(VfsRealFile).to eq(File)
24
+ end
25
+
26
+ it "should save reference to standard IO class" do
27
+ expect(Object.const_defined?(:VfsRealIO)).to be true
28
+ expect(VfsRealIO).to eq(IO)
29
+ end
30
+
31
+ it "should define VirtFS class" do
32
+ expect(Object.const_defined?(:VirtFS)).to be true
33
+ end
34
+
35
+ it "should define VirtFS::VDir class" do
36
+ expect(VirtFS.const_defined?(:VDir)).to be true
37
+ end
38
+
39
+ it "should define VirtFS::VFile class" do
40
+ expect(VirtFS.const_defined?(:File)).to be true
41
+ end
42
+
43
+ it "should define VirtFS::VIO class" do
44
+ expect(VirtFS.const_defined?(:IO)).to be true
45
+ end
46
+
47
+ describe ".activate!" do
48
+ it "should cause .activated? to return true" do
49
+ expect(VirtFS.activated?).to be false
50
+ VirtFS.activate!
51
+ expect(VirtFS.activated?).to be true
52
+ end
53
+
54
+ it "should set standard Dir class to VirtFS::Dir" do
55
+ expect(Dir).to eq(VfsRealDir)
56
+ VirtFS.activate!
57
+ expect(Dir).to eq(VirtFS::VDir)
58
+ end
59
+
60
+ it "should set standard File class to VirtFS::File" do
61
+ expect(File).to eq(VfsRealFile)
62
+ VirtFS.activate!
63
+ expect(File).to eq(VirtFS::VFile)
64
+ end
65
+
66
+ it "should set standard IO class to VirtFS::IO" do
67
+ expect(IO).to eq(VfsRealIO)
68
+ VirtFS.activate!
69
+ expect(IO).to eq(VirtFS::VIO)
70
+ end
71
+ end
72
+
73
+ describe ".deactivate!" do
74
+ before(:each) do
75
+ VirtFS.activate!
76
+ end
77
+
78
+ after(:each) do
79
+ VirtFS.deactivate! if VirtFS.activated?
80
+ end
81
+
82
+ it "should cause .activated? to return false" do
83
+ expect(VirtFS.activated?).to be true
84
+ VirtFS.deactivate!
85
+ expect(VirtFS.activated?).to be false
86
+ end
87
+
88
+ it "should set standard Dir class to VfsRealDir" do
89
+ expect(Dir).to eq(VirtFS::VDir)
90
+ VirtFS.deactivate!
91
+ expect(Dir).to eq(VfsRealDir)
92
+ end
93
+
94
+ it "should set standard File class to VfsRealFile" do
95
+ expect(File).to eq(VirtFS::VFile)
96
+ VirtFS.deactivate!
97
+ expect(File).to eq(VfsRealFile)
98
+ end
99
+
100
+ it "should set standard IO class to VfsRealDir" do
101
+ expect(IO).to eq(VirtFS::VIO)
102
+ VirtFS.deactivate!
103
+ expect(IO).to eq(VfsRealIO)
104
+ end
105
+ end
106
+
107
+ describe ".with" do
108
+ after(:each) do
109
+ VirtFS.deactivate! if VirtFS.activated?
110
+ end
111
+
112
+ it "should only be activated within block - when not activated initially" do
113
+ expect(VirtFS.activated?).to be false
114
+ VirtFS.with { expect(VirtFS.activated?).to be true }
115
+ expect(VirtFS.activated?).to be false
116
+ end
117
+
118
+ it "should remain activated - when activated initially" do
119
+ VirtFS.activate!
120
+ expect(VirtFS.activated?).to be true
121
+ VirtFS.with { expect(VirtFS.activated?).to be true }
122
+ expect(VirtFS.activated?).to be true
123
+ end
124
+ end
125
+
126
+ describe ".without" do
127
+ after(:each) do
128
+ VirtFS.deactivate! if VirtFS.activated?
129
+ end
130
+
131
+ it "should only be deactivated within block - when activated initially" do
132
+ VirtFS.activate!
133
+ expect(VirtFS.activated?).to be true
134
+ VirtFS.without { expect(VirtFS.activated?).to be false }
135
+ expect(VirtFS.activated?).to be true
136
+ end
137
+
138
+ it "should remain deactivated - when deactivated initially" do
139
+ expect(VirtFS.activated?).to be false
140
+ VirtFS.without { expect(VirtFS.activated?).to be false }
141
+ expect(VirtFS.activated?).to be false
142
+ end
143
+ end
144
+
145
+ describe "Dir objects" do
146
+ it "should identify as standard Dir - when not activated" do
147
+ Dir.open(__dir__) do |dir|
148
+ expect(dir).to be_kind_of(Dir)
149
+ expect(dir).to be_kind_of(VfsRealDir)
150
+ expect(dir).not_to be_kind_of(VirtFS::VDir)
151
+ end
152
+ end
153
+
154
+ it "should identify as VirtFS Dir - when activated" do
155
+ VirtFS.with do
156
+ Dir.open(__dir__) do |dir|
157
+ expect(dir).to be_kind_of(Dir)
158
+ expect(dir).to be_kind_of(VirtFS::VDir)
159
+ expect(dir).not_to be_kind_of(VfsRealDir)
160
+ end
161
+ end
162
+ end
163
+ end
164
+
165
+ describe "File objects" do
166
+ it "should identify as standard File - when not activated" do
167
+ File.open(__FILE__) do |file|
168
+ expect(file).to be_kind_of(File)
169
+ expect(file).to be_kind_of(VfsRealFile)
170
+ expect(file).not_to be_kind_of(VirtFS::VFile)
171
+ end
172
+ end
173
+
174
+ it "should identify as standard IO - when not activated" do
175
+ File.open(__FILE__) do |file|
176
+ expect(file).to be_kind_of(IO)
177
+ expect(file).to be_kind_of(VfsRealIO)
178
+ expect(file).not_to be_kind_of(VirtFS::VIO)
179
+ end
180
+ end
181
+
182
+ it "should identify as VirtFS File - when activated" do
183
+ VirtFS.with do
184
+ File.open(__FILE__) do |file|
185
+ expect(file).to be_kind_of(File)
186
+ expect(file).to be_kind_of(VirtFS::VFile)
187
+ expect(file).not_to be_kind_of(VfsRealFile)
188
+ end
189
+ end
190
+ end
191
+
192
+ it "should identify as VirtFS IO - when activated" do
193
+ VirtFS.with do
194
+ File.open(__FILE__) do |file|
195
+ expect(file).to be_kind_of(IO)
196
+ expect(file).to be_kind_of(VirtFS::VIO)
197
+ expect(file).not_to be_kind_of(VfsRealIO)
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end