memfs 0.4.1 → 0.4.2
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 +7 -0
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +7 -0
- data/Guardfile +5 -6
- data/README.md +6 -6
- data/Rakefile +9 -1
- data/lib/memfs.rb +6 -4
- data/lib/memfs/dir.rb +17 -21
- data/lib/memfs/fake/entry.rb +2 -2
- data/lib/memfs/fake/file/content.rb +3 -2
- data/lib/memfs/file.rb +54 -116
- data/lib/memfs/file/stat.rb +2 -2
- data/lib/memfs/file_system.rb +11 -13
- data/lib/memfs/io.rb +201 -0
- data/lib/memfs/version.rb +1 -1
- data/memfs.gemspec +17 -17
- data/memfs.png +0 -0
- data/spec/fileutils_spec.rb +233 -228
- data/spec/memfs/dir_spec.rb +76 -76
- data/spec/memfs/fake/directory_spec.rb +20 -20
- data/spec/memfs/fake/entry_spec.rb +24 -24
- data/spec/memfs/fake/file/content_spec.rb +43 -45
- data/spec/memfs/fake/file_spec.rb +14 -14
- data/spec/memfs/fake/symlink_spec.rb +22 -22
- data/spec/memfs/file/stat_spec.rb +314 -314
- data/spec/memfs/file_spec.rb +1636 -970
- data/spec/memfs/file_system_spec.rb +83 -83
- data/spec/memfs_spec.rb +15 -15
- data/spec/spec_helper.rb +17 -1
- metadata +36 -57
data/lib/memfs/file/stat.rb
CHANGED
@@ -21,7 +21,7 @@ module MemFs
|
|
21
21
|
:uid
|
22
22
|
|
23
23
|
def blockdev?
|
24
|
-
!!entry.block_device
|
24
|
+
!!(entry.block_device)
|
25
25
|
end
|
26
26
|
|
27
27
|
def chardev?
|
@@ -110,7 +110,7 @@ module MemFs
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def zero?
|
113
|
-
entry.content && entry.content.empty?
|
113
|
+
!!(entry.content && entry.content.empty?)
|
114
114
|
end
|
115
115
|
|
116
116
|
private
|
data/lib/memfs/file_system.rb
CHANGED
@@ -23,15 +23,13 @@ module MemFs
|
|
23
23
|
|
24
24
|
block.call if block
|
25
25
|
ensure
|
26
|
-
if block
|
27
|
-
self.working_directory = previous_directory
|
28
|
-
end
|
26
|
+
self.working_directory = previous_directory if block
|
29
27
|
end
|
30
28
|
|
31
29
|
def clear!
|
32
30
|
self.root = Fake::Directory.new('/')
|
33
|
-
|
34
|
-
|
31
|
+
mkdir '/tmp'
|
32
|
+
chdir '/'
|
35
33
|
end
|
36
34
|
|
37
35
|
def chmod(mode_int, file_name)
|
@@ -63,13 +61,13 @@ module MemFs
|
|
63
61
|
end
|
64
62
|
|
65
63
|
def find!(path)
|
66
|
-
find(path) ||
|
64
|
+
find(path) || fail(Errno::ENOENT, path)
|
67
65
|
end
|
68
66
|
|
69
67
|
def find_directory!(path)
|
70
68
|
entry = find!(path).dereferenced
|
71
69
|
|
72
|
-
|
70
|
+
fail Errno::ENOTDIR, path unless entry.is_a?(Fake::Directory)
|
73
71
|
|
74
72
|
entry
|
75
73
|
end
|
@@ -82,7 +80,7 @@ module MemFs
|
|
82
80
|
def getwd
|
83
81
|
working_directory.path
|
84
82
|
end
|
85
|
-
|
83
|
+
alias_method :pwd, :getwd
|
86
84
|
|
87
85
|
def initialize
|
88
86
|
clear!
|
@@ -91,7 +89,7 @@ module MemFs
|
|
91
89
|
def link(old_name, new_name)
|
92
90
|
file = find!(old_name)
|
93
91
|
|
94
|
-
|
92
|
+
fail Errno::EEXIST, "(#{old_name}, #{new_name})" if find(new_name)
|
95
93
|
|
96
94
|
link = file.dup
|
97
95
|
link.name = basename(new_name)
|
@@ -99,7 +97,7 @@ module MemFs
|
|
99
97
|
end
|
100
98
|
|
101
99
|
def mkdir(path)
|
102
|
-
|
100
|
+
fail Errno::EEXIST, path if find(path)
|
103
101
|
find_parent!(path).add_entry Fake::Directory.new(path)
|
104
102
|
end
|
105
103
|
|
@@ -118,13 +116,13 @@ module MemFs
|
|
118
116
|
def rmdir(path)
|
119
117
|
directory = find!(path)
|
120
118
|
|
121
|
-
|
119
|
+
fail Errno::ENOTEMPTY, path unless directory.empty?
|
122
120
|
|
123
121
|
directory.delete
|
124
122
|
end
|
125
123
|
|
126
124
|
def symlink(old_name, new_name)
|
127
|
-
|
125
|
+
fail Errno::EEXIST, new_name if find(new_name)
|
128
126
|
|
129
127
|
find_parent!(new_name).add_entry Fake::Symlink.new(new_name, old_name)
|
130
128
|
end
|
@@ -146,7 +144,7 @@ module MemFs
|
|
146
144
|
def unlink(path)
|
147
145
|
entry = find!(path)
|
148
146
|
|
149
|
-
|
147
|
+
fail Errno::EPERM, path if entry.is_a?(Fake::Directory)
|
150
148
|
|
151
149
|
entry.delete
|
152
150
|
end
|
data/lib/memfs/io.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'memfs/filesystem_access'
|
3
|
+
|
4
|
+
module MemFs
|
5
|
+
module IO
|
6
|
+
module ClassMethods
|
7
|
+
def read(path, *args)
|
8
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
9
|
+
options = { mode: File::RDONLY, encoding: nil, open_args: nil }.merge(options)
|
10
|
+
open_args = options[:open_args] ||
|
11
|
+
[options[:mode], encoding: options[:encoding]]
|
12
|
+
|
13
|
+
length, offset = args
|
14
|
+
|
15
|
+
file = open(path, *open_args)
|
16
|
+
file.seek(offset || 0)
|
17
|
+
file.read(length)
|
18
|
+
ensure
|
19
|
+
file.close if file
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module InstanceMethods
|
24
|
+
attr_writer :autoclose,
|
25
|
+
:close_on_exec
|
26
|
+
|
27
|
+
def <<(object)
|
28
|
+
fail IOError, 'not opened for writing' unless writable?
|
29
|
+
|
30
|
+
content << object.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def advise(advice_type, offset = 0, len = 0)
|
34
|
+
advice_types = [
|
35
|
+
:dontneed,
|
36
|
+
:noreuse,
|
37
|
+
:normal,
|
38
|
+
:random,
|
39
|
+
:sequential,
|
40
|
+
:willneed
|
41
|
+
]
|
42
|
+
unless advice_types.include?(advice_type)
|
43
|
+
fail NotImplementedError, "Unsupported advice: #{advice_type.inspect}"
|
44
|
+
end
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def autoclose?
|
49
|
+
@autoclose.nil? ? true : !!@autoclose
|
50
|
+
end
|
51
|
+
|
52
|
+
def binmode
|
53
|
+
@binmode = true
|
54
|
+
@external_encoding = Encoding::ASCII_8BIT
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def binmode?
|
59
|
+
@binmode.nil? ? false : @binmode
|
60
|
+
end
|
61
|
+
|
62
|
+
def close
|
63
|
+
self.closed = true
|
64
|
+
end
|
65
|
+
|
66
|
+
def closed?
|
67
|
+
closed
|
68
|
+
end
|
69
|
+
|
70
|
+
def close_on_exec?
|
71
|
+
@close_on_exec.nil? ? true : !!@close_on_exec
|
72
|
+
end
|
73
|
+
|
74
|
+
def eof?
|
75
|
+
pos >= content.size
|
76
|
+
end
|
77
|
+
alias_method :eof, :eof?
|
78
|
+
|
79
|
+
def external_encoding
|
80
|
+
if writable?
|
81
|
+
@external_encoding
|
82
|
+
else
|
83
|
+
@external_encoding ||= Encoding.default_external
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def each(sep = $/, &block)
|
88
|
+
return to_enum(__callee__) unless block_given?
|
89
|
+
fail IOError, 'not opened for reading' unless readable?
|
90
|
+
content.each_line(sep) { |line| block.call(line) }
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
def each_byte(&block)
|
95
|
+
return to_enum(__callee__) unless block_given?
|
96
|
+
fail IOError, 'not opened for reading' unless readable?
|
97
|
+
content.each_byte { |byte| block.call(byte) }
|
98
|
+
self
|
99
|
+
end
|
100
|
+
alias_method :bytes, :each_byte
|
101
|
+
|
102
|
+
def each_char(&block)
|
103
|
+
return to_enum(__callee__) unless block_given?
|
104
|
+
fail IOError, 'not opened for reading' unless readable?
|
105
|
+
content.each_char { |char| block.call(char) }
|
106
|
+
self
|
107
|
+
end
|
108
|
+
alias_method :chars, :each_char
|
109
|
+
|
110
|
+
def pos
|
111
|
+
entry.pos
|
112
|
+
end
|
113
|
+
|
114
|
+
def print(*objs)
|
115
|
+
$stdout.puts $_.inspect
|
116
|
+
objs << $_ if objs.empty?
|
117
|
+
self << objs.join($,) << $\.to_s
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
|
121
|
+
def printf(format_string, *objs)
|
122
|
+
print format_string % objs
|
123
|
+
end
|
124
|
+
|
125
|
+
def puts(text)
|
126
|
+
fail IOError, 'not opened for writing' unless writable?
|
127
|
+
|
128
|
+
content.puts text
|
129
|
+
end
|
130
|
+
|
131
|
+
def read(length = nil, buffer = '')
|
132
|
+
default = length ? nil : ''
|
133
|
+
content.read(length, buffer) || default
|
134
|
+
end
|
135
|
+
|
136
|
+
def seek(amount, whence = ::IO::SEEK_SET)
|
137
|
+
new_pos = case whence
|
138
|
+
when ::IO::SEEK_CUR then entry.pos + amount
|
139
|
+
when ::IO::SEEK_END then content.to_s.length + amount
|
140
|
+
when ::IO::SEEK_SET then amount
|
141
|
+
end
|
142
|
+
|
143
|
+
fail Errno::EINVAL, path if new_pos.nil? || new_pos < 0
|
144
|
+
|
145
|
+
entry.pos = new_pos
|
146
|
+
0
|
147
|
+
end
|
148
|
+
|
149
|
+
def stat
|
150
|
+
File.stat(path)
|
151
|
+
end
|
152
|
+
|
153
|
+
def write(string)
|
154
|
+
fail IOError, 'not opened for writing' unless writable?
|
155
|
+
|
156
|
+
content.write(string.to_s)
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
attr_accessor :closed,
|
162
|
+
:entry,
|
163
|
+
:opening_mode
|
164
|
+
|
165
|
+
attr_reader :path
|
166
|
+
|
167
|
+
def content
|
168
|
+
entry.content
|
169
|
+
end
|
170
|
+
|
171
|
+
def create_file?
|
172
|
+
(opening_mode & File::CREAT).nonzero?
|
173
|
+
end
|
174
|
+
|
175
|
+
def readable?
|
176
|
+
(opening_mode & File::RDWR).nonzero? ||
|
177
|
+
(opening_mode | File::RDONLY).zero?
|
178
|
+
end
|
179
|
+
|
180
|
+
def str_to_mode_int(mode)
|
181
|
+
return mode unless mode.is_a?(String)
|
182
|
+
|
183
|
+
unless mode =~ /\A([rwa]\+?)([bt])?\z/
|
184
|
+
fail ArgumentError, "invalid access mode #{mode}"
|
185
|
+
end
|
186
|
+
|
187
|
+
mode_str = $~[1]
|
188
|
+
File::MODE_MAP[mode_str]
|
189
|
+
end
|
190
|
+
|
191
|
+
def truncate_file?
|
192
|
+
(opening_mode & File::TRUNC).nonzero?
|
193
|
+
end
|
194
|
+
|
195
|
+
def writable?
|
196
|
+
(opening_mode & File::WRONLY).nonzero? ||
|
197
|
+
(opening_mode & File::RDWR).nonzero?
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
data/lib/memfs/version.rb
CHANGED
data/memfs.gemspec
CHANGED
@@ -4,28 +4,28 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'memfs/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
|
-
gem.name =
|
7
|
+
gem.name = 'memfs'
|
8
8
|
gem.version = MemFs::VERSION
|
9
|
-
gem.authors = [
|
10
|
-
gem.email = [
|
11
|
-
gem.description =
|
12
|
-
|
9
|
+
gem.authors = ['Simon COURTOIS']
|
10
|
+
gem.email = ['scourtois@cubyx.fr']
|
11
|
+
gem.description = 'MemFs provides a fake file system that can be used ' \
|
12
|
+
'for tests. Strongly inspired by FakeFS.'
|
13
13
|
gem.summary = "memfs-#{MemFs::VERSION}"
|
14
|
-
gem.homepage =
|
14
|
+
gem.homepage = 'http://github.com/simonc/memfs'
|
15
15
|
|
16
16
|
gem.license = 'MIT'
|
17
17
|
|
18
18
|
gem.files = `git ls-files`.split($/)
|
19
|
-
gem.executables = gem.files.grep(
|
20
|
-
gem.test_files = gem.files.grep(
|
21
|
-
gem.require_paths = [
|
19
|
+
gem.executables = gem.files.grep(/^bin\//).map { |f| File.basename(f) }
|
20
|
+
gem.test_files = gem.files.grep(/^(test|spec|features)\//)
|
21
|
+
gem.require_paths = ['lib']
|
22
22
|
|
23
|
-
gem.add_development_dependency
|
24
|
-
gem.add_development_dependency
|
25
|
-
gem.add_development_dependency
|
26
|
-
gem.add_development_dependency
|
27
|
-
gem.add_development_dependency
|
28
|
-
gem.add_development_dependency
|
29
|
-
gem.add_development_dependency
|
30
|
-
gem.add_development_dependency
|
23
|
+
gem.add_development_dependency 'coveralls', '~> 0.6'
|
24
|
+
gem.add_development_dependency 'rake', '~> 10.0'
|
25
|
+
gem.add_development_dependency 'rspec', '~> 3.0'
|
26
|
+
gem.add_development_dependency 'guard', '~> 2.6'
|
27
|
+
gem.add_development_dependency 'guard-rspec', '~> 4.3'
|
28
|
+
gem.add_development_dependency 'rb-inotify', '~> 0.8'
|
29
|
+
gem.add_development_dependency 'rb-fsevent', '~> 0.9'
|
30
|
+
gem.add_development_dependency 'rb-fchange', '~> 0.0'
|
31
31
|
end
|
data/memfs.png
ADDED
Binary file
|
data/spec/fileutils_spec.rb
CHANGED
@@ -15,86 +15,84 @@ describe FileUtils do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
describe '.cd' do
|
18
|
-
it
|
18
|
+
it 'changes the current working directory' do
|
19
19
|
FileUtils.cd '/test'
|
20
20
|
expect(FileUtils.pwd).to eq('/test')
|
21
21
|
end
|
22
22
|
|
23
|
-
it
|
23
|
+
it 'returns nil' do
|
24
24
|
expect(FileUtils.cd('/test')).to be_nil
|
25
25
|
end
|
26
26
|
|
27
27
|
it "raises an error when the given path doesn't exist" do
|
28
|
-
expect { FileUtils.cd('/nowhere') }.to
|
28
|
+
expect { FileUtils.cd('/nowhere') }.to raise_specific_error(Errno::ENOENT)
|
29
29
|
end
|
30
30
|
|
31
|
-
it
|
31
|
+
it 'raises an error when the given path is not a directory' do
|
32
32
|
FileUtils.touch('/test-file')
|
33
|
-
expect { FileUtils.cd('/test-file') }.to
|
33
|
+
expect { FileUtils.cd('/test-file') }.to raise_specific_error(Errno::ENOTDIR)
|
34
34
|
end
|
35
35
|
|
36
|
-
context
|
37
|
-
it
|
36
|
+
context 'when called with a block' do
|
37
|
+
it 'changes current working directory for the block execution' do
|
38
38
|
FileUtils.cd '/test' do
|
39
39
|
expect(FileUtils.pwd).to eq('/test')
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
it
|
43
|
+
it 'resumes to the old working directory after the block execution finished' do
|
44
44
|
FileUtils.cd '/'
|
45
|
-
expect {
|
46
|
-
FileUtils.cd('/test') {}
|
47
|
-
}.to_not change{FileUtils.pwd}
|
45
|
+
expect { FileUtils.cd('/test') {} }.to_not change { FileUtils.pwd }
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
|
-
context
|
49
|
+
context 'when the destination is a symlink' do
|
52
50
|
before :each do
|
53
51
|
FileUtils.symlink('/test', '/test-link')
|
54
52
|
end
|
55
53
|
|
56
|
-
it
|
54
|
+
it 'changes directory to the last target of the link chain' do
|
57
55
|
FileUtils.cd('/test-link')
|
58
56
|
expect(FileUtils.pwd).to eq('/test')
|
59
57
|
end
|
60
58
|
|
61
59
|
it "raises an error if the last target of the link chain doesn't exist" do
|
62
|
-
expect { FileUtils.cd('/nowhere-link') }.to
|
60
|
+
expect { FileUtils.cd('/nowhere-link') }.to raise_specific_error(Errno::ENOENT)
|
63
61
|
end
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
67
65
|
describe '.chmod' do
|
68
|
-
it
|
66
|
+
it 'changes permission bits on the named file to the bit pattern represented by mode' do
|
69
67
|
FileUtils.touch '/test-file'
|
70
68
|
FileUtils.chmod 0777, '/test-file'
|
71
69
|
expect(File.stat('/test-file').mode).to eq(0100777)
|
72
70
|
end
|
73
71
|
|
74
|
-
it
|
72
|
+
it 'changes permission bits on the named files (in list) to the bit pattern represented by mode' do
|
75
73
|
FileUtils.touch ['/test-file', '/test-file2']
|
76
74
|
FileUtils.chmod 0777, ['/test-file', '/test-file2']
|
77
75
|
expect(File.stat('/test-file2').mode).to eq(0100777)
|
78
76
|
end
|
79
77
|
|
80
|
-
it
|
78
|
+
it 'returns an array containing the file names' do
|
81
79
|
file_names = %w[/test-file /test-file2]
|
82
80
|
FileUtils.touch file_names
|
83
81
|
expect(FileUtils.chmod(0777, file_names)).to eq(file_names)
|
84
82
|
end
|
85
83
|
|
86
|
-
it
|
87
|
-
expect { FileUtils.chmod(0777, '/test-file') }.to
|
84
|
+
it 'raises an error if an entry does not exist' do
|
85
|
+
expect { FileUtils.chmod(0777, '/test-file') }.to raise_specific_error(Errno::ENOENT)
|
88
86
|
end
|
89
87
|
|
90
|
-
context
|
88
|
+
context 'when the named file is a symlink' do
|
91
89
|
before :each do
|
92
90
|
FileUtils.touch '/test-file'
|
93
91
|
FileUtils.symlink '/test-file', '/test-link'
|
94
92
|
end
|
95
93
|
|
96
|
-
context
|
97
|
-
it
|
94
|
+
context 'when File responds to lchmod' do
|
95
|
+
it 'changes the mode on the link' do
|
98
96
|
FileUtils.chmod(0777, '/test-link')
|
99
97
|
expect(File.lstat('/test-link').mode).to eq(0100777)
|
100
98
|
end
|
@@ -107,8 +105,9 @@ describe FileUtils do
|
|
107
105
|
end
|
108
106
|
|
109
107
|
context "when File doesn't respond to lchmod" do
|
110
|
-
it
|
111
|
-
FileUtils::Entry_
|
108
|
+
it 'does nothing' do
|
109
|
+
allow_any_instance_of(FileUtils::Entry_).to \
|
110
|
+
receive_messages(have_lchmod?: false)
|
112
111
|
mode = File.lstat('/test-link').mode
|
113
112
|
FileUtils.chmod(0777, '/test-link')
|
114
113
|
expect(File.lstat('/test-link').mode).to eq(mode)
|
@@ -122,40 +121,40 @@ describe FileUtils do
|
|
122
121
|
FileUtils.touch '/test/test-file'
|
123
122
|
end
|
124
123
|
|
125
|
-
it
|
124
|
+
it 'changes the permission bits on the named entry' do
|
126
125
|
FileUtils.chmod_R(0777, '/test')
|
127
126
|
expect(File.stat('/test').mode).to eq(0100777)
|
128
127
|
end
|
129
128
|
|
130
|
-
it
|
129
|
+
it 'changes the permission bits on any sub-directory of the named entry' do
|
131
130
|
FileUtils.chmod_R(0777, '/')
|
132
131
|
expect(File.stat('/test').mode).to eq(0100777)
|
133
132
|
end
|
134
133
|
|
135
|
-
it
|
134
|
+
it 'changes the permission bits on any descendant file of the named entry' do
|
136
135
|
FileUtils.chmod_R(0777, '/')
|
137
136
|
expect(File.stat('/test/test-file').mode).to eq(0100777)
|
138
137
|
end
|
139
138
|
end
|
140
139
|
|
141
140
|
describe '.chown' do
|
142
|
-
it
|
141
|
+
it 'changes owner on the named file' do
|
143
142
|
FileUtils.chown(42, nil, '/test')
|
144
143
|
expect(File.stat('/test').uid).to eq(42)
|
145
144
|
end
|
146
145
|
|
147
|
-
it
|
146
|
+
it 'changes owner on the named files (in list)' do
|
148
147
|
FileUtils.touch('/test-file')
|
149
148
|
FileUtils.chown(42, nil, ['/test', '/test-file'])
|
150
149
|
expect(File.stat('/test-file').uid).to eq(42)
|
151
150
|
end
|
152
151
|
|
153
|
-
it
|
152
|
+
it 'changes group on the named entry' do
|
154
153
|
FileUtils.chown(nil, 42, '/test')
|
155
154
|
expect(File.stat('/test').gid).to eq(42)
|
156
155
|
end
|
157
156
|
|
158
|
-
it
|
157
|
+
it 'changes group on the named entries in list' do
|
159
158
|
FileUtils.touch('/test-file')
|
160
159
|
FileUtils.chown(nil, 42, ['/test', '/test-file'])
|
161
160
|
expect(File.stat('/test-file').gid).to eq(42)
|
@@ -171,18 +170,18 @@ describe FileUtils do
|
|
171
170
|
expect(File.stat('/test').gid).not_to be(42)
|
172
171
|
end
|
173
172
|
|
174
|
-
context
|
173
|
+
context 'when the name entry is a symlink' do
|
175
174
|
before :each do
|
176
175
|
FileUtils.touch '/test-file'
|
177
176
|
FileUtils.symlink '/test-file', '/test-link'
|
178
177
|
end
|
179
178
|
|
180
|
-
it
|
179
|
+
it 'changes the owner on the last target of the link chain' do
|
181
180
|
FileUtils.chown(42, nil, '/test-link')
|
182
181
|
expect(File.stat('/test-file').uid).to eq(42)
|
183
182
|
end
|
184
183
|
|
185
|
-
it
|
184
|
+
it 'changes the group on the last target of the link chain' do
|
186
185
|
FileUtils.chown(nil, 42, '/test-link')
|
187
186
|
expect(File.stat('/test-file').gid).to eq(42)
|
188
187
|
end
|
@@ -204,32 +203,32 @@ describe FileUtils do
|
|
204
203
|
FileUtils.touch '/test/test-file'
|
205
204
|
end
|
206
205
|
|
207
|
-
it
|
206
|
+
it 'changes the owner on the named entry' do
|
208
207
|
FileUtils.chown_R(42, nil, '/test')
|
209
208
|
expect(File.stat('/test').uid).to eq(42)
|
210
209
|
end
|
211
210
|
|
212
|
-
it
|
211
|
+
it 'changes the group on the named entry' do
|
213
212
|
FileUtils.chown_R(nil, 42, '/test')
|
214
213
|
expect(File.stat('/test').gid).to eq(42)
|
215
214
|
end
|
216
215
|
|
217
|
-
it
|
216
|
+
it 'changes the owner on any sub-directory of the named entry' do
|
218
217
|
FileUtils.chown_R(42, nil, '/')
|
219
218
|
expect(File.stat('/test').uid).to eq(42)
|
220
219
|
end
|
221
220
|
|
222
|
-
it
|
221
|
+
it 'changes the group on any sub-directory of the named entry' do
|
223
222
|
FileUtils.chown_R(nil, 42, '/')
|
224
223
|
expect(File.stat('/test').gid).to eq(42)
|
225
224
|
end
|
226
225
|
|
227
|
-
it
|
226
|
+
it 'changes the owner on any descendant file of the named entry' do
|
228
227
|
FileUtils.chown_R(42, nil, '/')
|
229
228
|
expect(File.stat('/test/test-file').uid).to eq(42)
|
230
229
|
end
|
231
230
|
|
232
|
-
it
|
231
|
+
it 'changes the group on any descendant file of the named entry' do
|
233
232
|
FileUtils.chown_R(nil, 42, '/')
|
234
233
|
expect(File.stat('/test/test-file').gid).to eq(42)
|
235
234
|
end
|
@@ -240,40 +239,40 @@ describe FileUtils do
|
|
240
239
|
end
|
241
240
|
|
242
241
|
describe '.compare_file' do
|
243
|
-
it
|
244
|
-
File.open('/test-file', 'w') { |f| f.puts
|
245
|
-
File.open('/test-file2', 'w') { |f| f.puts
|
242
|
+
it 'returns true if the contents of a file A and a file B are identical' do
|
243
|
+
File.open('/test-file', 'w') { |f| f.puts 'this is a test' }
|
244
|
+
File.open('/test-file2', 'w') { |f| f.puts 'this is a test' }
|
246
245
|
|
247
|
-
expect(FileUtils.compare_file('/test-file', '/test-file2')).to
|
246
|
+
expect(FileUtils.compare_file('/test-file', '/test-file2')).to be true
|
248
247
|
end
|
249
248
|
|
250
|
-
it
|
251
|
-
File.open('/test-file', 'w') { |f| f.puts
|
252
|
-
File.open('/test-file2', 'w') { |f| f.puts
|
249
|
+
it 'returns false if the contents of a file A and a file B are not identical' do
|
250
|
+
File.open('/test-file', 'w') { |f| f.puts 'this is a test' }
|
251
|
+
File.open('/test-file2', 'w') { |f| f.puts 'this is not a test' }
|
253
252
|
|
254
|
-
expect(FileUtils.compare_file('/test-file', '/test-file2')).to
|
253
|
+
expect(FileUtils.compare_file('/test-file', '/test-file2')).to be false
|
255
254
|
end
|
256
255
|
end
|
257
256
|
|
258
257
|
describe '.compare_stream' do
|
259
|
-
it
|
260
|
-
File.open('/test-file', 'w') { |f| f.puts
|
261
|
-
File.open('/test-file2', 'w') { |f| f.puts
|
258
|
+
it 'returns true if the contents of a stream A and stream B are identical' do
|
259
|
+
File.open('/test-file', 'w') { |f| f.puts 'this is a test' }
|
260
|
+
File.open('/test-file2', 'w') { |f| f.puts 'this is a test' }
|
262
261
|
|
263
262
|
file1 = File.open('/test-file')
|
264
263
|
file2 = File.open('/test-file2')
|
265
264
|
|
266
|
-
expect(FileUtils.compare_stream(file1, file2)).to
|
265
|
+
expect(FileUtils.compare_stream(file1, file2)).to be true
|
267
266
|
end
|
268
267
|
|
269
|
-
it
|
270
|
-
File.open('/test-file', 'w') { |f| f.puts
|
271
|
-
File.open('/test-file2', 'w') { |f| f.puts
|
268
|
+
it 'returns false if the contents of a stream A and stream B are not identical' do
|
269
|
+
File.open('/test-file', 'w') { |f| f.puts 'this is a test' }
|
270
|
+
File.open('/test-file2', 'w') { |f| f.puts 'this is not a test' }
|
272
271
|
|
273
272
|
file1 = File.open('/test-file')
|
274
273
|
file2 = File.open('/test-file2')
|
275
274
|
|
276
|
-
expect(FileUtils.compare_stream(file1, file2)).to
|
275
|
+
expect(FileUtils.compare_stream(file1, file2)).to be false
|
277
276
|
end
|
278
277
|
end
|
279
278
|
|
@@ -282,57 +281,57 @@ describe FileUtils do
|
|
282
281
|
end
|
283
282
|
|
284
283
|
describe '.copy_entry' do
|
285
|
-
it
|
284
|
+
it 'copies a file system entry +src+ to +dest+' do
|
286
285
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
287
286
|
FileUtils.copy_entry('/test-file', '/test-copy')
|
288
287
|
expect(File.read('/test-copy')).to eq("test\n")
|
289
288
|
end
|
290
289
|
|
291
|
-
it
|
290
|
+
it 'preserves file types' do
|
292
291
|
FileUtils.touch('/test-file')
|
293
292
|
FileUtils.symlink('/test-file', '/test-link')
|
294
293
|
FileUtils.copy_entry('/test-link', '/test-copy')
|
295
|
-
expect(File.symlink?('/test-copy')).to
|
294
|
+
expect(File.symlink?('/test-copy')).to be true
|
296
295
|
end
|
297
296
|
|
298
|
-
context
|
299
|
-
it
|
297
|
+
context 'when +src+ does not exist' do
|
298
|
+
it 'raises an exception' do
|
300
299
|
expect {
|
301
300
|
FileUtils.copy_entry('/test-file', '/test-copy')
|
302
|
-
}.to
|
301
|
+
}.to raise_specific_error(RuntimeError)
|
303
302
|
end
|
304
303
|
end
|
305
304
|
|
306
|
-
context
|
305
|
+
context 'when +preserve+ is true' do
|
307
306
|
let(:time) { Date.parse('2013-01-01') }
|
308
307
|
|
309
308
|
before :each do
|
310
309
|
FileUtils.touch('/test-file')
|
311
310
|
FileUtils.chown(1042, 1042, '/test-file')
|
312
311
|
FileUtils.chmod(0777, '/test-file')
|
313
|
-
|
312
|
+
_fs.find('/test-file').mtime = time
|
314
313
|
FileUtils.copy_entry('/test-file', '/test-copy', true)
|
315
314
|
end
|
316
315
|
|
317
|
-
it
|
316
|
+
it 'preserves owner' do
|
318
317
|
expect(File.stat('/test-copy').uid).to eq(1042)
|
319
318
|
end
|
320
319
|
|
321
|
-
it
|
320
|
+
it 'preserves group' do
|
322
321
|
expect(File.stat('/test-copy').gid).to eq(1042)
|
323
322
|
end
|
324
323
|
|
325
|
-
it
|
324
|
+
it 'preserves permissions' do
|
326
325
|
expect(File.stat('/test-copy').mode).to eq(0100777)
|
327
326
|
end
|
328
327
|
|
329
|
-
it
|
328
|
+
it 'preserves modified time' do
|
330
329
|
expect(File.stat('/test-copy').mtime).to eq(time)
|
331
330
|
end
|
332
331
|
end
|
333
332
|
|
334
|
-
context
|
335
|
-
it
|
333
|
+
context 'when +dest+ already exists' do
|
334
|
+
it 'overwrite it' do
|
336
335
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
337
336
|
FileUtils.touch('/test-copy')
|
338
337
|
FileUtils.copy_entry('/test-file', '/test-copy')
|
@@ -340,25 +339,25 @@ describe FileUtils do
|
|
340
339
|
end
|
341
340
|
end
|
342
341
|
|
343
|
-
context
|
344
|
-
it
|
342
|
+
context 'when +remove_destination+ is true' do
|
343
|
+
it 'removes each destination file before copy' do
|
345
344
|
FileUtils.touch(['/test-file', '/test-copy'])
|
346
345
|
expect(File).to receive(:unlink).with('/test-copy')
|
347
346
|
FileUtils.copy_entry('/test-file', '/test-copy', false, false, true)
|
348
347
|
end
|
349
348
|
end
|
350
349
|
|
351
|
-
context
|
352
|
-
it
|
350
|
+
context 'when +src+ is a directory' do
|
351
|
+
it 'copies its contents recursively' do
|
353
352
|
FileUtils.mkdir_p('/test-dir/test-sub-dir')
|
354
353
|
FileUtils.copy_entry('/test-dir', '/test-copy')
|
355
|
-
expect(Dir.
|
354
|
+
expect(Dir.exist?('/test-copy/test-sub-dir')).to be true
|
356
355
|
end
|
357
356
|
end
|
358
357
|
end
|
359
358
|
|
360
359
|
describe '.copy_file' do
|
361
|
-
it
|
360
|
+
it 'copies file contents of src to dest' do
|
362
361
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
363
362
|
FileUtils.copy_file('/test-file', '/test-file2')
|
364
363
|
expect(File.read('/test-file2')).to eq("test\n")
|
@@ -374,70 +373,74 @@ describe FileUtils do
|
|
374
373
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
375
374
|
end
|
376
375
|
|
377
|
-
it
|
376
|
+
it 'copies a file content +src+ to +dest+' do
|
378
377
|
FileUtils.cp('/test-file', '/copy-file')
|
379
378
|
expect(File.read('/copy-file')).to eq("test\n")
|
380
379
|
end
|
381
380
|
|
382
|
-
context
|
383
|
-
it
|
384
|
-
expect {
|
381
|
+
context 'when +src+ and +dest+ are the same file' do
|
382
|
+
it 'raises an error' do
|
383
|
+
expect {
|
384
|
+
FileUtils.cp('/test-file', '/test-file')
|
385
|
+
}.to raise_specific_error(ArgumentError)
|
385
386
|
end
|
386
387
|
end
|
387
388
|
|
388
|
-
context
|
389
|
-
it
|
389
|
+
context 'when +dest+ is a directory' do
|
390
|
+
it 'copies +src+ to +dest/src+' do
|
390
391
|
FileUtils.mkdir('/dest')
|
391
392
|
FileUtils.cp('/test-file', '/dest/copy-file')
|
392
393
|
expect(File.read('/dest/copy-file')).to eq("test\n")
|
393
394
|
end
|
394
395
|
end
|
395
396
|
|
396
|
-
context
|
397
|
-
context
|
398
|
-
it
|
397
|
+
context 'when src is a list of files' do
|
398
|
+
context 'when +dest+ is not a directory' do
|
399
|
+
it 'raises an error' do
|
399
400
|
FileUtils.touch(['/dest', '/test-file2'])
|
400
|
-
expect {
|
401
|
+
expect {
|
402
|
+
FileUtils.cp(['/test-file', '/test-file2'], '/dest')
|
403
|
+
}.to raise_specific_error(Errno::ENOTDIR)
|
401
404
|
end
|
402
405
|
end
|
403
406
|
end
|
404
407
|
end
|
405
408
|
|
406
409
|
describe '.cp_r' do
|
407
|
-
it
|
410
|
+
it 'copies +src+ to +dest+' do
|
408
411
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
409
412
|
|
410
413
|
FileUtils.cp_r('/test-file', '/copy-file')
|
411
414
|
expect(File.read('/copy-file')).to eq("test\n")
|
412
415
|
end
|
413
416
|
|
414
|
-
context
|
415
|
-
it
|
417
|
+
context 'when +src+ is a directory' do
|
418
|
+
it 'copies all its contents recursively' do
|
416
419
|
FileUtils.mkdir('/test/dir')
|
417
420
|
FileUtils.touch('/test/dir/file')
|
418
421
|
|
419
422
|
FileUtils.cp_r('/test', '/dest')
|
420
|
-
expect(File.
|
423
|
+
expect(File.exist?('/dest/dir/file')).to be true
|
421
424
|
end
|
422
425
|
end
|
423
426
|
|
424
|
-
context
|
425
|
-
it
|
427
|
+
context 'when +dest+ is a directory' do
|
428
|
+
it 'copies +src+ to +dest/src+' do
|
426
429
|
FileUtils.mkdir(['/test/dir', '/dest'])
|
427
430
|
FileUtils.touch('/test/dir/file')
|
428
431
|
|
429
432
|
FileUtils.cp_r('/test', '/dest')
|
430
|
-
expect(File.
|
433
|
+
expect(File.exist?('/dest/test/dir/file')).to be true
|
431
434
|
end
|
432
435
|
end
|
433
436
|
|
434
|
-
context
|
435
|
-
it
|
437
|
+
context 'when +src+ is a list of files' do
|
438
|
+
it 'copies each of them in +dest+' do
|
436
439
|
FileUtils.mkdir(['/test/dir', '/test/dir2', '/dest'])
|
437
440
|
FileUtils.touch(['/test/dir/file', '/test/dir2/file'])
|
438
441
|
|
439
442
|
FileUtils.cp_r(['/test/dir', '/test/dir2'], '/dest')
|
440
|
-
expect(File.
|
443
|
+
expect(File.exist?('/dest/dir2/file')).to be true
|
441
444
|
end
|
442
445
|
end
|
443
446
|
end
|
@@ -455,34 +458,34 @@ describe FileUtils do
|
|
455
458
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
456
459
|
end
|
457
460
|
|
458
|
-
it
|
461
|
+
it 'copies +src+ to +dest+' do
|
459
462
|
FileUtils.install('/test-file', '/test-file2')
|
460
463
|
expect(File.read('/test-file2')).to eq("test\n")
|
461
464
|
end
|
462
465
|
|
463
|
-
context
|
464
|
-
it
|
466
|
+
context 'when +:mode+ is set' do
|
467
|
+
it 'changes the permission mode to +mode+' do
|
465
468
|
expect(File).to receive(:chmod).with(0777, '/test-file2')
|
466
469
|
FileUtils.install('/test-file', '/test-file2', mode: 0777)
|
467
470
|
end
|
468
471
|
end
|
469
472
|
|
470
|
-
context
|
471
|
-
it
|
473
|
+
context 'when +src+ and +dest+ are the same file' do
|
474
|
+
it 'raises an exception' do
|
472
475
|
expect {
|
473
476
|
FileUtils.install('/test-file', '/test-file')
|
474
477
|
}.to raise_exception(ArgumentError)
|
475
478
|
end
|
476
479
|
end
|
477
480
|
|
478
|
-
context
|
479
|
-
it
|
481
|
+
context 'when +dest+ already exists' do
|
482
|
+
it 'removes destination before copy' do
|
480
483
|
expect(File).to receive(:unlink).with('/test-file2')
|
481
484
|
FileUtils.install('/test-file', '/test-file2')
|
482
485
|
end
|
483
486
|
|
484
|
-
context
|
485
|
-
it
|
487
|
+
context 'and +dest+ is a directory' do
|
488
|
+
it 'installs +src+ in dest/src' do
|
486
489
|
FileUtils.mkdir('/test-dir')
|
487
490
|
FileUtils.install('/test-file', '/test-dir')
|
488
491
|
expect(File.read('/test-dir/test-file')).to eq("test\n")
|
@@ -500,33 +503,35 @@ describe FileUtils do
|
|
500
503
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
501
504
|
end
|
502
505
|
|
503
|
-
it
|
506
|
+
it 'creates a hard link +dest+ which points to +src+' do
|
504
507
|
FileUtils.ln('/test-file', '/test-file2')
|
505
508
|
expect(File.read('/test-file2')).to eq(File.read('/test-file'))
|
506
509
|
end
|
507
510
|
|
508
|
-
it
|
511
|
+
it 'creates a hard link, not a symlink' do
|
509
512
|
FileUtils.ln('/test-file', '/test-file2')
|
510
|
-
expect(File.symlink?('/test-file2')).to
|
513
|
+
expect(File.symlink?('/test-file2')).to be false
|
511
514
|
end
|
512
515
|
|
513
|
-
context
|
514
|
-
context
|
515
|
-
it
|
516
|
+
context 'when +dest+ already exists' do
|
517
|
+
context 'and is a directory' do
|
518
|
+
it 'creates a link dest/src' do
|
516
519
|
FileUtils.mkdir('/test-dir')
|
517
520
|
FileUtils.ln('/test-file', '/test-dir')
|
518
521
|
expect(File.read('/test-dir/test-file')).to eq(File.read('/test-file'))
|
519
522
|
end
|
520
523
|
end
|
521
524
|
|
522
|
-
context
|
523
|
-
it
|
525
|
+
context 'and it is not a directory' do
|
526
|
+
it 'raises an exception' do
|
524
527
|
FileUtils.touch('/test-file2')
|
525
|
-
expect {
|
528
|
+
expect {
|
529
|
+
FileUtils.ln('/test-file', '/test-file2')
|
530
|
+
}.to raise_specific_error(SystemCallError)
|
526
531
|
end
|
527
532
|
|
528
|
-
context
|
529
|
-
it
|
533
|
+
context 'and +:force+ is set' do
|
534
|
+
it 'overwrites +dest+' do
|
530
535
|
FileUtils.touch('/test-file2')
|
531
536
|
FileUtils.ln('/test-file', '/test-file2', force: true)
|
532
537
|
expect(File.read('/test-file2')).to eq(File.read('/test-file'))
|
@@ -535,19 +540,19 @@ describe FileUtils do
|
|
535
540
|
end
|
536
541
|
end
|
537
542
|
|
538
|
-
context
|
539
|
-
it
|
543
|
+
context 'when passing a list of paths' do
|
544
|
+
it 'creates a link for each path in +destdir+' do
|
540
545
|
FileUtils.touch('/test-file2')
|
541
546
|
FileUtils.mkdir('/test-dir')
|
542
547
|
FileUtils.ln(['/test-file', '/test-file2'], '/test-dir')
|
543
548
|
end
|
544
549
|
|
545
|
-
context
|
546
|
-
it
|
550
|
+
context 'and +destdir+ is not a directory' do
|
551
|
+
it 'raises an exception' do
|
547
552
|
FileUtils.touch(['/test-file2', '/not-a-dir'])
|
548
553
|
expect {
|
549
554
|
FileUtils.ln(['/test-file', '/test-file2'], '/not-a-dir')
|
550
|
-
}.to
|
555
|
+
}.to raise_specific_error(Errno::ENOTDIR)
|
551
556
|
end
|
552
557
|
end
|
553
558
|
end
|
@@ -560,67 +565,67 @@ describe FileUtils do
|
|
560
565
|
FileUtils.mkdir('/test-dir')
|
561
566
|
end
|
562
567
|
|
563
|
-
it
|
568
|
+
it 'creates a symbolic link +new+' do
|
564
569
|
FileUtils.ln_s('/test-file', '/test-link')
|
565
|
-
expect(File.symlink?('/test-link')).to
|
570
|
+
expect(File.symlink?('/test-link')).to be true
|
566
571
|
end
|
567
572
|
|
568
|
-
it
|
573
|
+
it 'creates a symbolic link which points to +old+' do
|
569
574
|
FileUtils.ln_s('/test-file', '/test-link')
|
570
575
|
expect(File.read('/test-link')).to eq(File.read('/test-file'))
|
571
576
|
end
|
572
577
|
|
573
|
-
context
|
574
|
-
context
|
575
|
-
it
|
578
|
+
context 'when +new+ already exists' do
|
579
|
+
context 'and it is a directory' do
|
580
|
+
it 'creates a symbolic link +new/old+' do
|
576
581
|
FileUtils.ln_s('/test-file', '/test-dir')
|
577
|
-
expect(File.symlink?('/test-dir/test-file')).to
|
582
|
+
expect(File.symlink?('/test-dir/test-file')).to be true
|
578
583
|
end
|
579
584
|
end
|
580
585
|
|
581
|
-
context
|
582
|
-
it
|
586
|
+
context 'and it is not a directory' do
|
587
|
+
it 'raises an exeption' do
|
583
588
|
expect {
|
584
589
|
FileUtils.ln_s('/test-file', '/not-a-dir')
|
585
|
-
}.to
|
590
|
+
}.to raise_specific_error(Errno::EEXIST)
|
586
591
|
end
|
587
592
|
|
588
|
-
context
|
589
|
-
it
|
593
|
+
context 'and +:force+ is set' do
|
594
|
+
it 'overwrites +new+' do
|
590
595
|
FileUtils.ln_s('/test-file', '/not-a-dir', force: true)
|
591
|
-
expect(File.symlink?('/not-a-dir')).to
|
596
|
+
expect(File.symlink?('/not-a-dir')).to be true
|
592
597
|
end
|
593
598
|
end
|
594
599
|
end
|
595
600
|
end
|
596
601
|
|
597
|
-
context
|
602
|
+
context 'when passing a list of paths' do
|
598
603
|
before :each do
|
599
604
|
File.open('/test-file2', 'w') { |f| f.puts 'test2' }
|
600
605
|
end
|
601
606
|
|
602
|
-
it
|
607
|
+
it 'creates several symbolic links in +destdir+' do
|
603
608
|
FileUtils.ln_s(['/test-file', '/test-file2'], '/test-dir')
|
604
|
-
expect(File.
|
609
|
+
expect(File.exist?('/test-dir/test-file2')).to be true
|
605
610
|
end
|
606
611
|
|
607
|
-
it
|
612
|
+
it 'creates symbolic links pointing to each item in the list' do
|
608
613
|
FileUtils.ln_s(['/test-file', '/test-file2'], '/test-dir')
|
609
614
|
expect(File.read('/test-dir/test-file2')).to eq(File.read('/test-file2'))
|
610
615
|
end
|
611
616
|
|
612
|
-
context
|
613
|
-
it
|
617
|
+
context 'when +destdir+ is not a directory' do
|
618
|
+
it 'raises an error' do
|
614
619
|
expect {
|
615
620
|
FileUtils.ln_s(['/test-file', '/test-file2'], '/not-a-dir')
|
616
|
-
}.to
|
621
|
+
}.to raise_specific_error(Errno::ENOTDIR)
|
617
622
|
end
|
618
623
|
end
|
619
624
|
end
|
620
625
|
end
|
621
626
|
|
622
627
|
describe '.ln_sf' do
|
623
|
-
it
|
628
|
+
it 'calls ln_s with +:force+ set to true' do
|
624
629
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
625
630
|
File.open('/test-file2', 'w') { |f| f.puts 'test2' }
|
626
631
|
FileUtils.ln_sf('/test-file', '/test-file2')
|
@@ -633,39 +638,39 @@ describe FileUtils do
|
|
633
638
|
end
|
634
639
|
|
635
640
|
describe '.mkdir' do
|
636
|
-
it
|
641
|
+
it 'creates one directory' do
|
637
642
|
FileUtils.mkdir('/test-dir')
|
638
|
-
expect(File.directory?('/test-dir')).to
|
643
|
+
expect(File.directory?('/test-dir')).to be true
|
639
644
|
end
|
640
645
|
|
641
|
-
context
|
642
|
-
it
|
646
|
+
context 'when passing a list of paths' do
|
647
|
+
it 'creates several directories' do
|
643
648
|
FileUtils.mkdir(['/test-dir', '/test-dir2'])
|
644
|
-
expect(File.directory?('/test-dir2')).to
|
649
|
+
expect(File.directory?('/test-dir2')).to be true
|
645
650
|
end
|
646
651
|
end
|
647
652
|
end
|
648
653
|
|
649
654
|
describe '.mkdir_p' do
|
650
|
-
it
|
655
|
+
it 'creates a directory' do
|
651
656
|
FileUtils.mkdir_p('/test-dir')
|
652
|
-
expect(File.directory?('/test-dir')).to
|
657
|
+
expect(File.directory?('/test-dir')).to be true
|
653
658
|
end
|
654
659
|
|
655
|
-
it
|
660
|
+
it 'creates all the parent directories' do
|
656
661
|
FileUtils.mkdir_p('/path/to/some/test-dir')
|
657
|
-
expect(File.directory?('/path/to/some')).to
|
662
|
+
expect(File.directory?('/path/to/some')).to be true
|
658
663
|
end
|
659
664
|
|
660
|
-
context
|
661
|
-
it
|
665
|
+
context 'when passing a list of paths' do
|
666
|
+
it 'creates each directory' do
|
662
667
|
FileUtils.mkdir_p(['/test-dir', '/test-dir'])
|
663
|
-
expect(File.directory?('/test-dir')).to
|
668
|
+
expect(File.directory?('/test-dir')).to be true
|
664
669
|
end
|
665
670
|
|
666
671
|
it "creates each directory's parents" do
|
667
672
|
FileUtils.mkdir_p(['/test-dir', '/path/to/some/test-dir'])
|
668
|
-
expect(File.directory?('/path/to/some')).to
|
673
|
+
expect(File.directory?('/path/to/some')).to be true
|
669
674
|
end
|
670
675
|
end
|
671
676
|
end
|
@@ -679,30 +684,30 @@ describe FileUtils do
|
|
679
684
|
end
|
680
685
|
|
681
686
|
describe '.mv' do
|
682
|
-
it
|
687
|
+
it 'moves +src+ to +dest+' do
|
683
688
|
FileUtils.touch('/test-file')
|
684
689
|
FileUtils.mv('/test-file', '/test-file2')
|
685
|
-
expect(File.
|
690
|
+
expect(File.exist?('/test-file2')).to be true
|
686
691
|
end
|
687
692
|
|
688
|
-
it
|
693
|
+
it 'removes +src+' do
|
689
694
|
FileUtils.touch('/test-file')
|
690
695
|
FileUtils.mv('/test-file', '/test-file2')
|
691
|
-
expect(File.
|
696
|
+
expect(File.exist?('/test-file')).to be false
|
692
697
|
end
|
693
698
|
|
694
|
-
context
|
695
|
-
context
|
696
|
-
it
|
699
|
+
context 'when +dest+ already exists' do
|
700
|
+
context 'and is a directory' do
|
701
|
+
it 'moves +src+ to dest/src' do
|
697
702
|
FileUtils.touch('/test-file')
|
698
703
|
FileUtils.mkdir('/test-dir')
|
699
704
|
FileUtils.mv('/test-file', '/test-dir')
|
700
|
-
expect(File.
|
705
|
+
expect(File.exist?('/test-dir/test-file')).to be true
|
701
706
|
end
|
702
707
|
end
|
703
708
|
|
704
|
-
context
|
705
|
-
it
|
709
|
+
context 'and +dest+ is not a directory' do
|
710
|
+
it 'it overwrites +dest+' do
|
706
711
|
File.open('/test-file', 'w') { |f| f.puts 'test' }
|
707
712
|
FileUtils.touch('/test-file2')
|
708
713
|
FileUtils.mv('/test-file', '/test-file2')
|
@@ -713,7 +718,7 @@ describe FileUtils do
|
|
713
718
|
end
|
714
719
|
|
715
720
|
describe '.pwd' do
|
716
|
-
it
|
721
|
+
it 'returns the name of the current directory' do
|
717
722
|
FileUtils.cd '/test'
|
718
723
|
expect(FileUtils.pwd).to eq('/test')
|
719
724
|
end
|
@@ -724,37 +729,37 @@ describe FileUtils do
|
|
724
729
|
end
|
725
730
|
|
726
731
|
describe '.remove_dir' do
|
727
|
-
it
|
732
|
+
it 'removes the given directory +dir+' do
|
728
733
|
FileUtils.mkdir('/test-dir')
|
729
734
|
FileUtils.remove_dir('/test-dir')
|
730
|
-
expect(File.
|
735
|
+
expect(File.exist?('/test-dir')).to be false
|
731
736
|
end
|
732
737
|
|
733
|
-
it
|
738
|
+
it 'removes the contents of the given directory +dir+' do
|
734
739
|
FileUtils.mkdir_p('/test-dir/test-sub-dir')
|
735
740
|
FileUtils.remove_dir('/test-dir')
|
736
|
-
expect(File.
|
741
|
+
expect(File.exist?('/test-dir/test-sub-dir')).to be false
|
737
742
|
end
|
738
743
|
|
739
|
-
context
|
740
|
-
it
|
744
|
+
context 'when +force+ is set' do
|
745
|
+
it 'ignores standard errors' do
|
741
746
|
expect { FileUtils.remove_dir('/test-dir', true) }.not_to raise_error
|
742
747
|
end
|
743
748
|
end
|
744
749
|
end
|
745
750
|
|
746
751
|
describe '.remove_entry' do
|
747
|
-
it
|
752
|
+
it 'removes a file system entry +path+' do
|
748
753
|
FileUtils.touch('/test-file')
|
749
754
|
FileUtils.remove_entry('/test-file')
|
750
|
-
expect(File.
|
755
|
+
expect(File.exist?('/test-file')).to be false
|
751
756
|
end
|
752
757
|
|
753
|
-
context
|
754
|
-
it
|
758
|
+
context 'when +path+ is a directory' do
|
759
|
+
it 'removes it recursively' do
|
755
760
|
FileUtils.mkdir_p('/test-dir/test-sub-dir')
|
756
761
|
FileUtils.remove_entry('/test-dir')
|
757
|
-
expect(Dir.
|
762
|
+
expect(Dir.exist?('/test-dir')).to be false
|
758
763
|
end
|
759
764
|
end
|
760
765
|
end
|
@@ -764,30 +769,30 @@ describe FileUtils do
|
|
764
769
|
FileUtils.mkdir_p('/test-dir/test-sub-dir')
|
765
770
|
end
|
766
771
|
|
767
|
-
it
|
772
|
+
it 'removes a file system entry +path+' do
|
768
773
|
FileUtils.chmod(0755, '/')
|
769
774
|
FileUtils.remove_entry_secure('/test-dir')
|
770
|
-
expect(Dir.
|
775
|
+
expect(Dir.exist?('/test-dir')).to be false
|
771
776
|
end
|
772
777
|
|
773
|
-
context
|
774
|
-
it
|
778
|
+
context 'when +path+ is a directory' do
|
779
|
+
it 'removes it recursively' do
|
775
780
|
FileUtils.chmod(0755, '/')
|
776
781
|
FileUtils.remove_entry_secure('/test-dir')
|
777
|
-
expect(Dir.
|
782
|
+
expect(Dir.exist?('/test-dir/test-sub-dir')).to be false
|
778
783
|
end
|
779
784
|
|
780
|
-
context
|
781
|
-
it
|
785
|
+
context 'and is word writable' do
|
786
|
+
it 'calls chown(2) on it' do
|
782
787
|
FileUtils.chmod(01777, '/')
|
783
|
-
directory =
|
788
|
+
directory = _fs.find('/test-dir')
|
784
789
|
expect(directory).to receive(:uid=).at_least(:once)
|
785
790
|
FileUtils.remove_entry_secure('/test-dir')
|
786
791
|
end
|
787
792
|
|
788
|
-
it
|
793
|
+
it 'calls chmod(2) on all sub directories' do
|
789
794
|
FileUtils.chmod(01777, '/')
|
790
|
-
directory =
|
795
|
+
directory = _fs.find('/test-dir')
|
791
796
|
expect(directory).to receive(:mode=).at_least(:once)
|
792
797
|
FileUtils.remove_entry_secure('/test-dir')
|
793
798
|
end
|
@@ -796,49 +801,49 @@ describe FileUtils do
|
|
796
801
|
end
|
797
802
|
|
798
803
|
describe '.remove_file' do
|
799
|
-
it
|
804
|
+
it 'removes a file path' do
|
800
805
|
FileUtils.touch('/test-file')
|
801
806
|
FileUtils.remove_file('/test-file')
|
802
|
-
expect(File.
|
807
|
+
expect(File.exist?('/test-file')).to be false
|
803
808
|
end
|
804
809
|
|
805
|
-
context
|
806
|
-
it
|
810
|
+
context 'when +force+ is set' do
|
811
|
+
it 'ignores StandardError' do
|
807
812
|
expect { FileUtils.remove_file('/no-file', true) }.not_to raise_error
|
808
813
|
end
|
809
814
|
end
|
810
815
|
end
|
811
816
|
|
812
817
|
describe '.rm' do
|
813
|
-
it
|
818
|
+
it 'removes the specified file' do
|
814
819
|
FileUtils.touch('/test-file')
|
815
820
|
FileUtils.rm('/test-file')
|
816
|
-
expect(File.
|
821
|
+
expect(File.exist?('/test-file')).to be false
|
817
822
|
end
|
818
823
|
|
819
|
-
it
|
824
|
+
it 'removes files specified in list' do
|
820
825
|
FileUtils.touch(['/test-file', '/test-file2'])
|
821
826
|
FileUtils.rm(['/test-file', '/test-file2'])
|
822
|
-
expect(File.
|
827
|
+
expect(File.exist?('/test-file2')).to be false
|
823
828
|
end
|
824
829
|
|
825
|
-
it
|
830
|
+
it 'cannot remove a directory' do
|
826
831
|
FileUtils.mkdir('/test-dir')
|
827
|
-
expect { FileUtils.rm('/test-dir') }.to
|
832
|
+
expect { FileUtils.rm('/test-dir') }.to raise_specific_error(Errno::EPERM)
|
828
833
|
end
|
829
834
|
|
830
|
-
context
|
831
|
-
it
|
835
|
+
context 'when +:force+ is set' do
|
836
|
+
it 'ignores StandardError' do
|
832
837
|
FileUtils.mkdir('/test-dir')
|
833
838
|
expect {
|
834
839
|
FileUtils.rm('/test-dir', force: true)
|
835
|
-
}.not_to raise_error
|
840
|
+
}.not_to raise_error
|
836
841
|
end
|
837
842
|
end
|
838
843
|
end
|
839
844
|
|
840
845
|
describe '.rm_f' do
|
841
|
-
it
|
846
|
+
it 'calls rm with +:force+ set to true' do
|
842
847
|
expect(FileUtils).to receive(:rm).with('test', force: true)
|
843
848
|
FileUtils.rm_f('test')
|
844
849
|
end
|
@@ -849,63 +854,63 @@ describe FileUtils do
|
|
849
854
|
FileUtils.touch(['/test-file', '/test-file2'])
|
850
855
|
end
|
851
856
|
|
852
|
-
it
|
857
|
+
it 'removes a list of files' do
|
853
858
|
FileUtils.rm_r(['/test-file', '/test-file2'])
|
854
|
-
expect(File.
|
859
|
+
expect(File.exist?('/test-file2')).to be false
|
855
860
|
end
|
856
861
|
|
857
|
-
context
|
858
|
-
it
|
862
|
+
context 'when an item of the list is a directory' do
|
863
|
+
it 'removes all its contents recursively' do
|
859
864
|
FileUtils.mkdir('/test-dir')
|
860
865
|
FileUtils.touch('/test-dir/test-file')
|
861
866
|
FileUtils.rm_r(['/test-file', '/test-file2', '/test-dir'])
|
862
|
-
expect(File.
|
867
|
+
expect(File.exist?('/test-dir/test-file')).to be false
|
863
868
|
end
|
864
869
|
end
|
865
870
|
|
866
|
-
context
|
867
|
-
it
|
871
|
+
context 'when +:force+ is set' do
|
872
|
+
it 'ignores StandardError' do
|
868
873
|
expect {
|
869
874
|
FileUtils.rm_r(['/no-file'], force: true)
|
870
|
-
}.not_to raise_error
|
875
|
+
}.not_to raise_error
|
871
876
|
end
|
872
877
|
end
|
873
878
|
end
|
874
879
|
|
875
880
|
describe '.rm_rf' do
|
876
|
-
it
|
881
|
+
it 'calls rm with +:force+ set to true' do
|
877
882
|
expect(FileUtils).to receive(:rm_r).with('test', force: true)
|
878
883
|
FileUtils.rm_rf('test')
|
879
884
|
end
|
880
885
|
end
|
881
886
|
|
882
887
|
describe '.rmdir' do
|
883
|
-
it
|
888
|
+
it 'Removes a directory' do
|
884
889
|
FileUtils.mkdir('/test-dir')
|
885
890
|
FileUtils.rmdir('/test-dir')
|
886
|
-
expect(Dir.
|
891
|
+
expect(Dir.exist?('/test-dir')).to be false
|
887
892
|
end
|
888
893
|
|
889
|
-
it
|
894
|
+
it 'Removes a list of directories' do
|
890
895
|
FileUtils.mkdir('/test-dir')
|
891
896
|
FileUtils.mkdir('/test-dir2')
|
892
897
|
FileUtils.rmdir(['/test-dir', '/test-dir2'])
|
893
|
-
expect(Dir.
|
898
|
+
expect(Dir.exist?('/test-dir2')).to be false
|
894
899
|
end
|
895
900
|
|
896
|
-
context
|
901
|
+
context 'when a directory is not empty' do
|
897
902
|
before :each do
|
898
903
|
FileUtils.mkdir('/test-dir')
|
899
904
|
FileUtils.touch('/test-dir/test-file')
|
900
905
|
end
|
901
906
|
|
902
|
-
it
|
907
|
+
it 'ignores errors' do
|
903
908
|
expect { FileUtils.rmdir('/test-dir') }.not_to raise_error
|
904
909
|
end
|
905
910
|
|
906
911
|
it "doesn't remove the directory" do
|
907
912
|
FileUtils.rmdir('/test-dir')
|
908
|
-
expect(Dir.
|
913
|
+
expect(Dir.exist?('/test-dir')).to be true
|
909
914
|
end
|
910
915
|
end
|
911
916
|
end
|
@@ -925,12 +930,12 @@ describe FileUtils do
|
|
925
930
|
describe '.touch' do
|
926
931
|
it "creates a file if it doesn't exist" do
|
927
932
|
FileUtils.touch('/test-file')
|
928
|
-
expect(
|
933
|
+
expect(_fs.find('/test-file')).not_to be_nil
|
929
934
|
end
|
930
935
|
|
931
936
|
it "creates a list of files if they don't exist" do
|
932
937
|
FileUtils.touch(['/test-file', '/test-file2'])
|
933
|
-
expect(
|
938
|
+
expect(_fs.find('/test-file2')).not_to be_nil
|
934
939
|
end
|
935
940
|
end
|
936
941
|
|
@@ -938,23 +943,23 @@ describe FileUtils do
|
|
938
943
|
before :each do
|
939
944
|
FileUtils.touch('/test-file')
|
940
945
|
FileUtils.touch('/old-file')
|
941
|
-
|
946
|
+
_fs.find!('/old-file').mtime = Time.now - 3600
|
942
947
|
end
|
943
948
|
|
944
|
-
it
|
945
|
-
expect(FileUtils.uptodate?('/test-file', ['/old-file'])).to
|
949
|
+
it 'returns true if +newer+ is newer than all +old_list+' do
|
950
|
+
expect(FileUtils.uptodate?('/test-file', ['/old-file'])).to be true
|
946
951
|
end
|
947
952
|
|
948
|
-
context
|
949
|
-
it
|
950
|
-
expect(FileUtils.uptodate?('/no-file', ['/old-file'])).to
|
953
|
+
context 'when +newer+ does not exist' do
|
954
|
+
it 'consideres it as older' do
|
955
|
+
expect(FileUtils.uptodate?('/no-file', ['/old-file'])).to be false
|
951
956
|
end
|
952
957
|
end
|
953
958
|
|
954
|
-
context
|
955
|
-
it
|
959
|
+
context 'when a item of +old_list+ does not exist' do
|
960
|
+
it 'consideres it as older than +newer+' do
|
956
961
|
uptodate = FileUtils.uptodate?('/test-file', ['/old-file', '/no-file'])
|
957
|
-
expect(uptodate).to
|
962
|
+
expect(uptodate).to be true
|
958
963
|
end
|
959
964
|
end
|
960
965
|
end
|