benry-unixcommand 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES.md +20 -0
- data/MIT-LICENSE +21 -0
- data/README.md +1063 -0
- data/benry-unixcommand.gemspec +31 -0
- data/doc/benry-unixcommand.html +932 -0
- data/doc/css/style.css +168 -0
- data/lib/benry/unixcommand.rb +1322 -0
- data/test/run_all.rb +14 -0
- data/test/unixcommand_test.rb +2517 -0
- metadata +69 -0
@@ -0,0 +1,2517 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
libpath = File.class_eval { join(dirname(dirname(__FILE__)), 'lib') }
|
4
|
+
$LOAD_PATH << libpath unless $LOAD_PATH.include?(libpath)
|
5
|
+
|
6
|
+
require 'oktest'
|
7
|
+
require 'stringio'
|
8
|
+
require 'etc'
|
9
|
+
|
10
|
+
require 'benry/unixcommand'
|
11
|
+
require 'fileutils'
|
12
|
+
|
13
|
+
|
14
|
+
Oktest.scope do
|
15
|
+
|
16
|
+
|
17
|
+
topic Benry::UnixCommand do
|
18
|
+
include Benry::UnixCommand
|
19
|
+
|
20
|
+
before_all do
|
21
|
+
FileUtils.rm_rf "tmpdir"
|
22
|
+
FileUtils.mkdir "tmpdir"
|
23
|
+
end
|
24
|
+
|
25
|
+
after_all do
|
26
|
+
FileUtils.rm_rf "tmpdir"
|
27
|
+
end
|
28
|
+
|
29
|
+
before do
|
30
|
+
@_backto = Dir.pwd
|
31
|
+
Dir.chdir "tmpdir"
|
32
|
+
File.write("foo1.txt", "FOO1")
|
33
|
+
File.write("foo2.txt", "FOO2")
|
34
|
+
FileUtils.mkdir "d1"
|
35
|
+
File.write("d1/bar.txt", "BAR")
|
36
|
+
FileUtils.mkdir "d1/d2"
|
37
|
+
File.write("d1/d2/baz.txt", "BAZ")
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
Dir.chdir @_backto
|
42
|
+
FileUtils.rm_rf Dir.glob("tmpdir/*")
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
topic 'prompt()' do
|
47
|
+
spec "[!uilyk] returns prompt string." do
|
48
|
+
ok {prompt()} == "$ "
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
topic 'prompt!()' do
|
53
|
+
spec "[!q992e] adds indentation after prompt." do
|
54
|
+
ok {prompt!(0)} == "$ "
|
55
|
+
ok {prompt!(1)} == "$ "
|
56
|
+
ok {prompt!(2)} == "$ "
|
57
|
+
ok {prompt!(3)} == "$ "
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
topic 'echoback()' do
|
63
|
+
spec "[!x7atu] prints argument string into $stdout with prompt." do
|
64
|
+
sout, serr = capture_sio() do
|
65
|
+
echoback "foo bar baz"
|
66
|
+
end
|
67
|
+
ok {sout} == "$ foo bar baz\n"
|
68
|
+
ok {serr} == ""
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
topic '__echoback?()' do
|
73
|
+
spec "[!ik00u] returns value of `@__BENRY_ECHOBACK` or `$BENRY_ECHOBACK`." do
|
74
|
+
bkup = $BENRY_ECHOBACK
|
75
|
+
at_end { $BENRY_ECHOBACK = bkup }
|
76
|
+
#
|
77
|
+
ok {instance_variable_defined?(:@__BENRY_ECHOBACK)} == false
|
78
|
+
$BENRY_ECHOBACK = true
|
79
|
+
ok {__echoback?()} == true
|
80
|
+
$BENRY_ECHOBACK = false
|
81
|
+
ok {__echoback?()} == false
|
82
|
+
end
|
83
|
+
spec "[!1hp69] instance var `@__BENRY_ECHOBACK` is prior than `$BENRY_ECHOBACK`." do
|
84
|
+
bkup = $BENRY_ECHOBACK
|
85
|
+
at_end { $BENRY_ECHOBACK = bkup }
|
86
|
+
#
|
87
|
+
$BENRY_ECHOBACK = true
|
88
|
+
@__BENRY_ECHOBACK = false
|
89
|
+
ok {__echoback?()} == false
|
90
|
+
$BENRY_ECHOBACK = false
|
91
|
+
@__BENRY_ECHOBACK = true
|
92
|
+
ok {__echoback?()} == true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def _sysout(command)
|
97
|
+
sout, serr = capture_sio { sys command }
|
98
|
+
ok {serr} == ""
|
99
|
+
return sout
|
100
|
+
end
|
101
|
+
|
102
|
+
topic 'echoback_on()' do
|
103
|
+
spec "[!9x2lh] enables echoback temporarily." do
|
104
|
+
bkup = $BENRY_ECHOBACK
|
105
|
+
at_end { $BENRY_ECHOBACK = bkup }
|
106
|
+
#
|
107
|
+
$BENRY_ECHOBACK = false
|
108
|
+
ok {__echoback?()} == false
|
109
|
+
ok {_sysout "echo ABC >/dev/null"} == ""
|
110
|
+
echoback_on do
|
111
|
+
ok {__echoback?()} == true
|
112
|
+
ok {_sysout "echo ABC >/dev/null"} == "$ echo ABC >/dev/null\n"
|
113
|
+
end
|
114
|
+
ok {__echoback?()} == false
|
115
|
+
ok {_sysout "echo ABC >/dev/null"} == ""
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
topic 'echoback_off()' do
|
120
|
+
spec "[!prkfg] disables echoback temporarily." do
|
121
|
+
bkup = $BENRY_ECHOBACK
|
122
|
+
at_end { $BENRY_ECHOBACK = bkup }
|
123
|
+
#
|
124
|
+
$BENRY_ECHOBACK = true
|
125
|
+
ok {__echoback?()} == true
|
126
|
+
ok {_sysout "echo ABC >/dev/null"} == "$ echo ABC >/dev/null\n"
|
127
|
+
echoback_off do
|
128
|
+
ok {__echoback?()} == false
|
129
|
+
ok {_sysout "echo ABC >/dev/null"} == ""
|
130
|
+
end
|
131
|
+
ok {__echoback?()} == true
|
132
|
+
ok {_sysout "echo ABC >/dev/null"} == "$ echo ABC >/dev/null\n"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
topic 'echoback_switch()' do
|
137
|
+
spec "[!aw9b2] switches on/off of echoback temporarily." do
|
138
|
+
bkup = $BENRY_ECHOBACK
|
139
|
+
at_end { $BENRY_ECHOBACK = bkup }
|
140
|
+
#
|
141
|
+
$BENRY_ECHOBACK = true
|
142
|
+
ok {__echoback?()} == true
|
143
|
+
echoback_switch(false) do
|
144
|
+
ok {__echoback?()} == false
|
145
|
+
echoback_switch(true) do
|
146
|
+
ok {__echoback?()} == true
|
147
|
+
echoback_switch(false) do
|
148
|
+
ok {__echoback?()} == false
|
149
|
+
end
|
150
|
+
ok {__echoback?()} == true
|
151
|
+
end
|
152
|
+
ok {__echoback?()} == false
|
153
|
+
end
|
154
|
+
ok {__echoback?()} == true
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
topic 'echo()' do
|
159
|
+
spec "[!mzbdj] echoback command arguments." do
|
160
|
+
sout, serr = capture_sio do
|
161
|
+
echo "foo", "bar"
|
162
|
+
end
|
163
|
+
ok {sout} == ("$ echo foo bar\n"\
|
164
|
+
"foo bar\n")
|
165
|
+
end
|
166
|
+
spec "[!cjggd] prints arguments." do
|
167
|
+
sout, serr = capture_sio do
|
168
|
+
echo "abc", 123, true, nil
|
169
|
+
end
|
170
|
+
ok {sout} == ("$ echo abc 123 true \n"\
|
171
|
+
"abc 123 true \n")
|
172
|
+
end
|
173
|
+
spec "[!vhpw3] not print newline at end if '-n' option specified." do
|
174
|
+
sout, serr = capture_sio do
|
175
|
+
echo :n, "abc"
|
176
|
+
end
|
177
|
+
ok {sout} == ("$ echo -n abc\n"\
|
178
|
+
"abc")
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
topic 'sys()' do
|
184
|
+
spec "[!fb1ji] error if both array and string are specified at the same time." do
|
185
|
+
pr = proc { sys ["echo", "AA"], "BB" }
|
186
|
+
ok {pr}.raise?(ArgumentError,
|
187
|
+
"sys: Invalid argument (if arg is specified as an array, other args should not be specified).")
|
188
|
+
#
|
189
|
+
pr = proc { sys :q, ["echo", "AA"], "BB" }
|
190
|
+
ok {pr}.raise?(ArgumentError,
|
191
|
+
"sys: Invalid argument (if arg is specified as an array, other args should not be specified).")
|
192
|
+
#
|
193
|
+
pr = proc { sys! ["echo", "AA"], "BB" }
|
194
|
+
ok {pr}.raise?(ArgumentError,
|
195
|
+
"sys!: Invalid argument (if arg is specified as an array, other args should not be specified).")
|
196
|
+
end
|
197
|
+
spec "[!rqe7a] echoback command and arguments when `:p` not specified." do
|
198
|
+
sout, serr = capture_sio do
|
199
|
+
sys "echo foo bar >/dev/null"
|
200
|
+
end
|
201
|
+
ok {sout} == "$ echo foo bar >/dev/null\n"
|
202
|
+
end
|
203
|
+
spec "[!ptipz] not echoback command and arguments when `:p` specified." do
|
204
|
+
sout, serr = capture_sio do
|
205
|
+
sys :q, "echo foo bar >/dev/null"
|
206
|
+
end
|
207
|
+
ok {sout} == ""
|
208
|
+
end
|
209
|
+
spec "[!4u9lj] arguments in echoback string should be quoted or escaped." do
|
210
|
+
tmpf = "tmp.#{rand().to_s[2..6]}"
|
211
|
+
at_end { File.unlink(tmpf) if File.exist?(tmpf) }
|
212
|
+
ruby = "ruby -r ../lib/benry/unixcommand.rb"
|
213
|
+
setup = "include Benry::UnixCommand"
|
214
|
+
## multiple string
|
215
|
+
system %Q|#{ruby} -e '#{setup}; sys "echo", "A B C"' > #{tmpf}|
|
216
|
+
ok {File.read(tmpf)} == ("$ echo \"A B C\"\n" \
|
217
|
+
"A B C\n")
|
218
|
+
## one array
|
219
|
+
system %Q|#{ruby} -e '#{setup}; sys ["echo", "A B C"]' > #{tmpf}|
|
220
|
+
ok {File.read(tmpf)} == ("$ echo \"A B C\"\n" \
|
221
|
+
"A B C\n")
|
222
|
+
end
|
223
|
+
spec "[!dccme] accepts one string, one array, or multiple strings." do
|
224
|
+
tmpf = "tmp.#{rand().to_s[2..6]}"
|
225
|
+
at_end { File.unlink(tmpf) if File.exist?(tmpf) }
|
226
|
+
ruby = "ruby -r ../lib/benry/unixcommand.rb"
|
227
|
+
setup = "include Benry::UnixCommand"
|
228
|
+
## multiple string
|
229
|
+
system %Q|#{ruby} -e '#{setup}; sys :q, "echo", "AA", "BB", "CC"' > #{tmpf}|
|
230
|
+
ok {File.read(tmpf)} == "AA BB CC\n"
|
231
|
+
## one array
|
232
|
+
system %Q|#{ruby} -e '#{setup}; sys :q, ["echo", "AA", "BB", "CC"]' > #{tmpf}|
|
233
|
+
ok {File.read(tmpf)} == "AA BB CC\n"
|
234
|
+
end
|
235
|
+
spec "[!r9ne3] shell is not invoked if arg is one array or multiple string." do
|
236
|
+
tmpf = "tmp.#{rand().to_s[2..6]}"
|
237
|
+
at_end { File.unlink(tmpf) if File.exist?(tmpf) }
|
238
|
+
ruby = "ruby -r ../lib/benry/unixcommand.rb"
|
239
|
+
setup = "include Benry::UnixCommand"
|
240
|
+
## multiple string
|
241
|
+
system %Q|#{ruby} -e '#{setup}; sys :q, "echo", "ABC", "<", ">"' > #{tmpf}|
|
242
|
+
ok {File.read(tmpf)} == "ABC < >\n"
|
243
|
+
## one array
|
244
|
+
system %Q|#{ruby} -e '#{setup}; sys :q, ["echo", "ABC", "*", ">"]' > #{tmpf}|
|
245
|
+
ok {File.read(tmpf)} == "ABC * >\n"
|
246
|
+
## multiple string
|
247
|
+
sout, serr = capture_sio do
|
248
|
+
pr = proc { sys "echo AA BB", " > tmp1.txt" }
|
249
|
+
ok {pr}.raise?(RuntimeError,
|
250
|
+
"Command failed with status (127): \"echo AA BB\" \" > tmp1.txt\"")
|
251
|
+
end
|
252
|
+
ok {sout} == "$ \"echo AA BB\" \" > tmp1.txt\"\n"
|
253
|
+
ok {serr} == ""
|
254
|
+
## one array
|
255
|
+
sout, serr = capture_sio do
|
256
|
+
pr = proc { sys ["echo AA BB > tmp1.txt"] }
|
257
|
+
ok {pr}.raise?(RuntimeError,
|
258
|
+
"Command failed with status (127): \"echo AA BB > tmp1.txt\"")
|
259
|
+
end
|
260
|
+
ok {sout} == "$ \"echo AA BB > tmp1.txt\"\n"
|
261
|
+
ok {serr} == ""
|
262
|
+
end
|
263
|
+
spec "[!w6ol7] globbing is enabled when arg is multiple string." do
|
264
|
+
tmpf = "tmp.#{rand().to_s[2..6]}"
|
265
|
+
at_end { File.unlink(tmpf) if File.exist?(tmpf) }
|
266
|
+
ruby = "ruby -r ../lib/benry/unixcommand.rb"
|
267
|
+
setup = "include Benry::UnixCommand"
|
268
|
+
## multiple string
|
269
|
+
system %Q|#{ruby} -e '#{setup}; sys "echo", "**/*.txt"' > #{tmpf}|
|
270
|
+
ok {File.read(tmpf)} == (
|
271
|
+
"$ echo **/*.txt\n"\
|
272
|
+
"d1/bar.txt d1/d2/baz.txt foo1.txt foo2.txt\n"
|
273
|
+
)
|
274
|
+
end
|
275
|
+
spec "[!ifgkd] globbing is disabled when arg is one array." do
|
276
|
+
tmpf = "tmp.#{rand().to_s[2..6]}"
|
277
|
+
at_end { File.unlink(tmpf) if File.exist?(tmpf) }
|
278
|
+
ruby = "ruby -r ../lib/benry/unixcommand.rb"
|
279
|
+
setup = "include Benry::UnixCommand"
|
280
|
+
## one array
|
281
|
+
system %Q|#{ruby} -e '#{setup}; sys ["echo", "**/*.txt"]' > #{tmpf}|
|
282
|
+
ok {File.read(tmpf)} == (
|
283
|
+
"$ echo **/*.txt\n"\
|
284
|
+
"**/*.txt\n"
|
285
|
+
)
|
286
|
+
end
|
287
|
+
spec "[!agntr] returns process status if command succeeded." do
|
288
|
+
sout, serr = capture_sio do
|
289
|
+
ret = sys "echo foo bar >/dev/null"
|
290
|
+
ok {ret}.is_a?(Process::Status)
|
291
|
+
ok {ret.exitstatus} == 0
|
292
|
+
end
|
293
|
+
end
|
294
|
+
spec "[!clfig] yields block if command failed." do
|
295
|
+
sout, serr = capture_sio do
|
296
|
+
called = false
|
297
|
+
stat = sys "false" do |stat|
|
298
|
+
called = true
|
299
|
+
end
|
300
|
+
ok {called} == true
|
301
|
+
ok {stat.exitstatus} == 1
|
302
|
+
end
|
303
|
+
end
|
304
|
+
spec "[!deu3e] not yield block if command succeeded." do
|
305
|
+
sout, serr = capture_sio do
|
306
|
+
called = false
|
307
|
+
ret = sys "true" do |stat|
|
308
|
+
called = true
|
309
|
+
end
|
310
|
+
ok {called} == false
|
311
|
+
ok {ret.exitstatus} == 0
|
312
|
+
end
|
313
|
+
end
|
314
|
+
spec "[!chko8] block argument is process status." do
|
315
|
+
sout, serr = capture_sio do
|
316
|
+
arg = nil
|
317
|
+
ret = sys "false" do |stat|
|
318
|
+
arg = stat
|
319
|
+
true
|
320
|
+
end
|
321
|
+
ok {arg}.is_a?(Process::Status)
|
322
|
+
ok {arg}.same?(ret)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
spec "[!0yy6r] (sys) not raise error if block result is truthy" do
|
326
|
+
sout, serr = capture_sio do
|
327
|
+
pr = proc { sys "false" do true end }
|
328
|
+
ok {pr}.NOT.raise?(ArgumentError)
|
329
|
+
pr = proc { sys "false" do false end }
|
330
|
+
ok {pr}.raise?(RuntimeError, "Command failed with status (1): false")
|
331
|
+
end
|
332
|
+
end
|
333
|
+
spec "[!xsspi] (sys) raises error if command failed." do
|
334
|
+
sout, serr = capture_sio do
|
335
|
+
pr = proc { sys "grep -q ^FOOBAR foo1.txt" }
|
336
|
+
ok {pr}.raise?(RuntimeError, "Command failed with status (1): grep -q ^FOOBAR foo1.txt")
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
topic 'sys!()' do
|
342
|
+
spec "[!tbfii] (sys!) returns process status if command failed." do
|
343
|
+
sout, serr = capture_sio do
|
344
|
+
ret = sys! "grep -q ^FOOBAR foo1.txt"
|
345
|
+
ok {ret}.is_a?(Process::Status)
|
346
|
+
ok {ret.exitstatus} == 1
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
topic '__system()' do
|
352
|
+
before do
|
353
|
+
@tmpf = "tmp.#{rand().to_s[2..6]}"
|
354
|
+
at_end { File.unlink(@tmpf) if File.exist?(@tmpf) }
|
355
|
+
end
|
356
|
+
spec "[!9xarc] invokes command without shell when `shell:` is falty." do
|
357
|
+
result = __system("echo A B > #{@tmpf}", shell: false)
|
358
|
+
ok {result} == nil
|
359
|
+
ok {@tmpf}.not_exist?
|
360
|
+
end
|
361
|
+
spec "[!0z33p] invokes command with shell (if necessary) when `shell:` is truthy." do
|
362
|
+
result = __system("echo A B > #{@tmpf}", shell: true)
|
363
|
+
ok {result} == true
|
364
|
+
ok {@tmpf}.file_exist?
|
365
|
+
ok {File.read(@tmpf)} == "A B\n"
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
topic '__build_echoback_str()' do
|
370
|
+
spec "[!4dcra] if arg is one array, quotes or escapes arguments." do
|
371
|
+
s = __build_echoback_str([["echo", "A B C", "D\"E'F\"'", "*.txt"]])
|
372
|
+
ok {s} == %q`echo "A B C" D\"E\'F\"\' *.txt`
|
373
|
+
end
|
374
|
+
spec "[!ueoov] if arg is multiple string, quotes or escapes arguments." do
|
375
|
+
s = __build_echoback_str(["echo", "A B C", "D\"E'F\"'", "*.txt"])
|
376
|
+
ok {s} == %q`echo "A B C" D\"E\'F\"\' *.txt`
|
377
|
+
end
|
378
|
+
spec "[!hnp41] if arg is one string, not quote nor escape argument." do
|
379
|
+
s = __build_echoback_str(["echo \"A B C\" D\"E'F\"' *.txt"])
|
380
|
+
ok {s} == %q`echo "A B C" D"E'F"' *.txt`
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
topic 'glob_if_possible()' do
|
385
|
+
spec "[!xvr32] expands file pattern matching." do
|
386
|
+
ok {glob_if_possible("*.txt")} == ["foo1.txt", "foo2.txt"]
|
387
|
+
ok {glob_if_possible("**/*.txt")} == ["d1/bar.txt", "d1/d2/baz.txt", "foo1.txt", "foo2.txt"]
|
388
|
+
ok {glob_if_possible("foo?.*", "**/bar.*")} == ["foo1.txt", "foo2.txt", "d1/bar.txt"]
|
389
|
+
end
|
390
|
+
spec "[!z38re] if pattern not matched to any files, just returns pattern as is." do
|
391
|
+
ok {glob_if_possible("blabla*", "*.xhtml")} == ["blabla*", "*.xhtml"]
|
392
|
+
ok {glob_if_possible("*.css", "*.txt")} == ["*.css", "foo1.txt", "foo2.txt"]
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
topic 'ruby()' do
|
397
|
+
spec "[!98qro] echoback command and args." do
|
398
|
+
sout, serr = capture_sio do
|
399
|
+
ruby "-e", "x=0"
|
400
|
+
end
|
401
|
+
ok {sout} == "$ #{RbConfig.ruby} -e x=0\n"
|
402
|
+
end
|
403
|
+
spec "[!u5f5l] run ruby command." do
|
404
|
+
sout, serr = capture_sio do
|
405
|
+
ruby "-e 'File.write(\"out1\", \"ABC\")'"
|
406
|
+
ruby "-e", "File.write(\"out2\", \"XYZ\")"
|
407
|
+
end
|
408
|
+
ok {sout} == ("$ #{RbConfig.ruby} -e 'File.write(\"out1\", \"ABC\")'\n"\
|
409
|
+
"$ #{RbConfig.ruby} -e \"File.write(\\\"out2\\\", \\\"XYZ\\\")\"\n")
|
410
|
+
ok {File.read("out1")} == "ABC"
|
411
|
+
ok {File.read("out2")} == "XYZ"
|
412
|
+
end
|
413
|
+
spec "[!2jano] returns process status object if ruby command succeeded." do
|
414
|
+
sout, serr = capture_sio do
|
415
|
+
ret = ruby "-e", "x = 1"
|
416
|
+
ok {ret}.is_a?(Process::Status)
|
417
|
+
ok {ret.exitstatus} == 0
|
418
|
+
end
|
419
|
+
end
|
420
|
+
spec "[!69clt] (ruby) error when ruby command failed." do
|
421
|
+
sout, serr = capture_sio do
|
422
|
+
pr = proc { ruby "-e '1/0' 2> err1" }
|
423
|
+
ok {pr}.raise?(RuntimeError, "Command failed with status (1): #{RbConfig.ruby} -e '1/0' 2> err1")
|
424
|
+
ok {File.read("err1")} =~ /ZeroDivisionError/
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
topic 'ruby!()' do
|
430
|
+
spec "[!z1f03] (ruby!) ignores error even when ruby command failed." do
|
431
|
+
sout, serr = capture_sio do
|
432
|
+
ret = nil
|
433
|
+
pr = proc { ret = ruby! "-e '1/0' 2> err1" }
|
434
|
+
ok {pr}.NOT.raise?(RuntimeError)
|
435
|
+
ok {File.read("err1")} =~ /ZeroDivisionError/
|
436
|
+
ok {ret}.is_a?(Process::Status)
|
437
|
+
ok {ret.exitstatus} == 1
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
|
443
|
+
topic 'popen2()', tag: 'open3' do
|
444
|
+
spec "[!8que2] calls 'Open3.popen2()'." do
|
445
|
+
expected = (" 1 AA\n"\
|
446
|
+
" 2 BB\n"\
|
447
|
+
" 3 CC\n")
|
448
|
+
#
|
449
|
+
sout, serr = capture_sio do
|
450
|
+
arr = popen2("cat -n")
|
451
|
+
ok {arr}.length(3)
|
452
|
+
stdin, stdout, wait_thread = arr
|
453
|
+
stdin.write("AA\nBB\nCC\n")
|
454
|
+
stdin.close()
|
455
|
+
output = stdout.read()
|
456
|
+
ok {output} == expected
|
457
|
+
end
|
458
|
+
ok {sout} == "$ cat -n\n"
|
459
|
+
ok {serr} == ""
|
460
|
+
#
|
461
|
+
sout, serr = capture_sio do
|
462
|
+
output2 = popen2("cat -n") do |*args|
|
463
|
+
ok {args}.length(3)
|
464
|
+
stdin, stdout, wait_thread = args
|
465
|
+
stdin.write("AA\nBB\nCC\n")
|
466
|
+
stdin.close()
|
467
|
+
stdout.read()
|
468
|
+
end
|
469
|
+
ok {output2} == expected
|
470
|
+
end
|
471
|
+
ok {sout} == "$ cat -n\n"
|
472
|
+
ok {serr} == ""
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
topic 'popen2e()', tag: 'open3' do
|
477
|
+
spec "[!s6g1r] calls 'Open3.popen2e()'." do
|
478
|
+
expected = (" 1 AA\n"\
|
479
|
+
" 2 BB\n"\
|
480
|
+
" 3 CC\n"\
|
481
|
+
" 0.00 real 0.00 user 0.00 sys\n")
|
482
|
+
#
|
483
|
+
sout, serr = capture_sio do
|
484
|
+
arr = popen2e("time cat -n")
|
485
|
+
ok {arr}.length(3)
|
486
|
+
stdin, stdout, wait_thread = arr
|
487
|
+
stdin.write("AA\nBB\nCC\n")
|
488
|
+
stdin.close()
|
489
|
+
output = stdout.read()
|
490
|
+
ok {output} == expected
|
491
|
+
end
|
492
|
+
ok {sout} == "$ time cat -n\n"
|
493
|
+
ok {serr} == ""
|
494
|
+
#
|
495
|
+
sout, serr = capture_sio do
|
496
|
+
output2 = popen2e("time cat -n") do |*args|
|
497
|
+
ok {args}.length(3)
|
498
|
+
stdin, stdout, wait_thread = args
|
499
|
+
stdin.write("AA\nBB\nCC\n")
|
500
|
+
stdin.close()
|
501
|
+
stdout.read()
|
502
|
+
end
|
503
|
+
ok {output2} == expected
|
504
|
+
end
|
505
|
+
ok {sout} == "$ time cat -n\n"
|
506
|
+
ok {serr} == ""
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
topic 'popen3()', tag: 'open3' do
|
511
|
+
spec "[!evlx7] calls 'Open3.popen3()'." do
|
512
|
+
expected1 = (" 1 AA\n"\
|
513
|
+
" 2 BB\n"\
|
514
|
+
" 3 CC\n")
|
515
|
+
expected2 = " 0.00 real 0.00 user 0.00 sys\n"
|
516
|
+
#
|
517
|
+
sout, serr = capture_sio do
|
518
|
+
arr = popen3("time cat -n")
|
519
|
+
ok {arr}.length(4)
|
520
|
+
stdin, stdout, stderr, wait_thread = arr
|
521
|
+
stdin.write("AA\nBB\nCC\n")
|
522
|
+
stdin.close()
|
523
|
+
ok {stdout.read()} == expected1
|
524
|
+
ok {stderr.read()} == expected2
|
525
|
+
end
|
526
|
+
ok {sout} == "$ time cat -n\n"
|
527
|
+
ok {serr} == ""
|
528
|
+
#
|
529
|
+
sout, serr = capture_sio do
|
530
|
+
output, error = popen3("time cat -n") do |*args|
|
531
|
+
ok {args}.length(4)
|
532
|
+
stdin, stdout, stderr, wait_thread = args
|
533
|
+
stdin.write("AA\nBB\nCC\n")
|
534
|
+
stdin.close()
|
535
|
+
[stdout.read(), stderr.read()]
|
536
|
+
end
|
537
|
+
ok {output} == expected1
|
538
|
+
ok {error} == expected2
|
539
|
+
end
|
540
|
+
ok {sout} == "$ time cat -n\n"
|
541
|
+
ok {serr} == ""
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
topic 'capture2()', tag: 'open3' do
|
546
|
+
spec "[!5p4dw] calls 'Open3.capture2()'." do
|
547
|
+
expected = (" 1 AA\n"\
|
548
|
+
" 2 BB\n"\
|
549
|
+
" 3 CC\n")
|
550
|
+
#
|
551
|
+
sout, serr = capture_sio do
|
552
|
+
output = capture2("cat -n", stdin_data: "AA\nBB\nCC\n")
|
553
|
+
ok {output} == expected
|
554
|
+
end
|
555
|
+
ok {sout} == "$ cat -n\n"
|
556
|
+
ok {serr} == ""
|
557
|
+
end
|
558
|
+
spec "[!2s1by] error when command failed." do
|
559
|
+
sout, serr = capture_sio do
|
560
|
+
pr = proc { capture2("grep -q FOOBAR foo1.txt") }
|
561
|
+
ok {pr}.raise?(RuntimeError, "Command failed with status (1): grep -q FOOBAR foo1.txt")
|
562
|
+
end
|
563
|
+
ok {sout} == "$ grep -q FOOBAR foo1.txt\n"
|
564
|
+
ok {serr} == ""
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
topic 'capture2e()', tag: 'open3' do
|
569
|
+
spec "[!jgn71] calls 'Open3.capture2e()'." do
|
570
|
+
expected = (" 1 AA\n"\
|
571
|
+
" 2 BB\n"\
|
572
|
+
" 3 CC\n"\
|
573
|
+
" 0.00 real 0.00 user 0.00 sys\n")
|
574
|
+
#
|
575
|
+
sout, serr = capture_sio do
|
576
|
+
output = capture2e("time cat -n", stdin_data: "AA\nBB\nCC\n")
|
577
|
+
ok {output} == expected
|
578
|
+
end
|
579
|
+
ok {sout} == "$ time cat -n\n"
|
580
|
+
ok {serr} == ""
|
581
|
+
end
|
582
|
+
spec "[!qr3ka] error when command failed." do
|
583
|
+
sout, serr = capture_sio do
|
584
|
+
pr = proc { capture2e("grep -q FOOBAR foo1.txt") }
|
585
|
+
ok {pr}.raise?(RuntimeError, "Command failed with status (1): grep -q FOOBAR foo1.txt")
|
586
|
+
end
|
587
|
+
ok {sout} == "$ grep -q FOOBAR foo1.txt\n"
|
588
|
+
ok {serr} == ""
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
topic 'capture3()', tag: 'open3' do
|
593
|
+
spec "[!n91rh] calls 'Open3.capture3()'." do
|
594
|
+
expected1 = (" 1 AA\n"\
|
595
|
+
" 2 BB\n"\
|
596
|
+
" 3 CC\n")
|
597
|
+
expected2 = " 0.00 real 0.00 user 0.00 sys\n"
|
598
|
+
#
|
599
|
+
sout, serr = capture_sio do
|
600
|
+
output, error = capture3("time cat -n", stdin_data: "AA\nBB\nCC\n")
|
601
|
+
ok {output} == expected1
|
602
|
+
ok {error} == expected2
|
603
|
+
end
|
604
|
+
ok {sout} == "$ time cat -n\n"
|
605
|
+
ok {serr} == ""
|
606
|
+
end
|
607
|
+
spec "[!thnyv] error when command failed." do
|
608
|
+
sout, serr = capture_sio do
|
609
|
+
pr = proc { capture3("grep -q FOOBAR foo1.txt") }
|
610
|
+
ok {pr}.raise?(RuntimeError, "Command failed with status (1): grep -q FOOBAR foo1.txt")
|
611
|
+
end
|
612
|
+
ok {sout} == "$ grep -q FOOBAR foo1.txt\n"
|
613
|
+
ok {serr} == ""
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
topic 'capture2!()', tag: 'open3' do
|
618
|
+
spec "[!357e1] ignore errors even if command failed." do
|
619
|
+
sout, serr = capture_sio do
|
620
|
+
output, process_status = capture2!("grep -q FOOBAR foo1.txt")
|
621
|
+
ok {process_status.exitstatus} == 1
|
622
|
+
ok {output} == ""
|
623
|
+
end
|
624
|
+
ok {sout} == "$ grep -q FOOBAR foo1.txt\n"
|
625
|
+
ok {serr} == ""
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
topic 'capture2e!()', tag: 'open3' do
|
630
|
+
spec "[!o0b7c] ignore errors even if command failed." do
|
631
|
+
sout, serr = capture_sio do
|
632
|
+
output, process_status = capture2e!("grep -q FOOBAR blabla.txt")
|
633
|
+
ok {process_status.exitstatus} == 2
|
634
|
+
ok {output} == "grep: blabla.txt: No such file or directory\n"
|
635
|
+
end
|
636
|
+
ok {sout} == "$ grep -q FOOBAR blabla.txt\n"
|
637
|
+
ok {serr} == ""
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
topic 'capture3()', tag: 'open3' do
|
642
|
+
spec "[!rwfiu] ignore errors even if command failed." do
|
643
|
+
sout, serr = capture_sio do
|
644
|
+
output, error, process_status = capture3!("grep -q FOOBAR blabla.txt")
|
645
|
+
ok {process_status.exitstatus} == 2
|
646
|
+
ok {output} == ""
|
647
|
+
ok {error} == "grep: blabla.txt: No such file or directory\n"
|
648
|
+
end
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
|
653
|
+
topic 'cd()' do
|
654
|
+
spec "[!gnmdg] expands file pattern." do
|
655
|
+
sout, serr = capture_sio do
|
656
|
+
here = Dir.pwd
|
657
|
+
cd "d?"
|
658
|
+
ok {Dir.pwd} == File.join(here, "d1")
|
659
|
+
end
|
660
|
+
end
|
661
|
+
spec "[!v7bn7] error when pattern not matched to any file." do
|
662
|
+
sout, serr = capture_sio do
|
663
|
+
pr = proc { cd "blabla*" }
|
664
|
+
ok {pr}.raise?(ArgumentError, "cd: blabla*: directory not found.")
|
665
|
+
end
|
666
|
+
end
|
667
|
+
spec "[!08wuv] error when pattern matched to multiple files." do
|
668
|
+
sout, serr = capture_sio do
|
669
|
+
pr = proc { cd "foo*" }
|
670
|
+
ok {pr}.raise?(ArgumentError, "cd: foo*: unexpectedly matched to multiple filenames (foo1.txt, foo2.txt).")
|
671
|
+
end
|
672
|
+
end
|
673
|
+
spec "[!hs7u8] error when argument is not a directory name." do
|
674
|
+
sout, serr = capture_sio do
|
675
|
+
pr = proc { cd "foo1.txt" }
|
676
|
+
ok {pr}.raise?(ArgumentError, "cd: foo1.txt: Not a directory.")
|
677
|
+
end
|
678
|
+
end
|
679
|
+
spec "[!cg5ns] changes current directory." do
|
680
|
+
here = Dir.pwd
|
681
|
+
begin
|
682
|
+
sout, serr = capture_sio() do
|
683
|
+
cd "d1/d2"
|
684
|
+
ok {Dir.pwd} == here + "/d1/d2"
|
685
|
+
end
|
686
|
+
ok {Dir.pwd} == here + "/d1/d2"
|
687
|
+
ok {sout} == <<-END.gsub(/^ */, '')
|
688
|
+
$ cd d1/d2
|
689
|
+
END
|
690
|
+
ok {serr} == ""
|
691
|
+
ensure
|
692
|
+
Dir.chdir(here)
|
693
|
+
end
|
694
|
+
end
|
695
|
+
spec "[!uit6q] if block given, then back to current dir." do
|
696
|
+
here = Dir.pwd
|
697
|
+
sout, serr = capture_sio() do
|
698
|
+
cd "d1" do
|
699
|
+
ok {Dir.pwd} == here + "/d1"
|
700
|
+
cd "d2" do
|
701
|
+
ok {Dir.pwd} == here + "/d1/d2"
|
702
|
+
end
|
703
|
+
ok {Dir.pwd} == here + "/d1"
|
704
|
+
end
|
705
|
+
ok {Dir.pwd} == here
|
706
|
+
end
|
707
|
+
ok {sout} == <<-END.gsub(/^ */, '')
|
708
|
+
$ cd d1
|
709
|
+
$ cd d2
|
710
|
+
$ cd -
|
711
|
+
$ cd -
|
712
|
+
END
|
713
|
+
ok {serr} == ""
|
714
|
+
end
|
715
|
+
spec "[!cg298] returns path before changing directory." do
|
716
|
+
here = Dir.pwd
|
717
|
+
path = nil
|
718
|
+
ret = nil
|
719
|
+
capture_sio() do
|
720
|
+
ret = cd "d1/d2" do
|
721
|
+
path = Dir.pwd
|
722
|
+
end
|
723
|
+
end
|
724
|
+
ok {ret} == here
|
725
|
+
ok {ret} != path
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
|
730
|
+
topic 'pushd()' do
|
731
|
+
spec "[!nvkha] expands file pattern." do
|
732
|
+
sout, serr = capture_sio do
|
733
|
+
here = Dir.pwd
|
734
|
+
pushd "d?" do
|
735
|
+
ok {Dir.pwd} == File.join(here, "d1")
|
736
|
+
end
|
737
|
+
end
|
738
|
+
end
|
739
|
+
spec "[!q3itn] error when pattern not matched to any file." do
|
740
|
+
sout, serr = capture_sio do
|
741
|
+
pr = proc { pushd "blabla*" do end }
|
742
|
+
ok {pr}.raise?(ArgumentError, "pushd: blabla*: directory not found.")
|
743
|
+
end
|
744
|
+
end
|
745
|
+
spec "[!hveaj] error when pattern matched to multiple files." do
|
746
|
+
sout, serr = capture_sio do
|
747
|
+
pr = proc { pushd "foo*" do end }
|
748
|
+
ok {pr}.raise?(ArgumentError, "pushd: foo*: unexpectedly matched to multiple filenames (foo1.txt, foo2.txt).")
|
749
|
+
end
|
750
|
+
end
|
751
|
+
spec "[!y6cq9] error when argument is not a directory name." do
|
752
|
+
sout, serr = capture_sio do
|
753
|
+
pr = proc { pushd "foo1.txt" do end }
|
754
|
+
ok {pr}.raise?(ArgumentError, "pushd: foo1.txt: Not a directory.")
|
755
|
+
end
|
756
|
+
end
|
757
|
+
#
|
758
|
+
spec "[!7ksfd] replaces home path with '~'." do
|
759
|
+
home = home2 = nil
|
760
|
+
sout, serr = capture_sio do
|
761
|
+
home = File.expand_path("~")
|
762
|
+
ok {home} != "~"
|
763
|
+
pushd home do
|
764
|
+
puts Dir.pwd
|
765
|
+
home2 = Dir.pwd
|
766
|
+
pushd "/" do
|
767
|
+
puts Dir.pwd
|
768
|
+
end
|
769
|
+
end
|
770
|
+
end
|
771
|
+
skip_when home != home2, "home directory may be a symbolic link"
|
772
|
+
ok {sout} =~ /^\$ popd \# back to ~$/
|
773
|
+
end
|
774
|
+
spec "[!xl6lg] raises error when block not given." do
|
775
|
+
pr = proc { pushd "d1/d2" }
|
776
|
+
ok {pr}.raise?(ArgumentError, "pushd: requires block argument.")
|
777
|
+
end
|
778
|
+
spec "[!rxtd0] changes directory and yields block." do
|
779
|
+
here = Dir.pwd
|
780
|
+
path = nil
|
781
|
+
sout, serr = capture_sio do
|
782
|
+
pushd "d1/d2" do
|
783
|
+
path = Dir.pwd
|
784
|
+
end
|
785
|
+
end
|
786
|
+
home = File.expand_path('~')
|
787
|
+
here2 = here.start_with?(home) ? here.sub(home, '~') : here
|
788
|
+
ok {path} != nil
|
789
|
+
ok {path} != here
|
790
|
+
ok {path} == File.join(here, "d1/d2")
|
791
|
+
ok {sout} == ("$ pushd d1/d2\n"\
|
792
|
+
"$ popd # back to #{here2}\n")
|
793
|
+
end
|
794
|
+
spec "[!9jszw] back to origin directory after yielding block." do
|
795
|
+
here = Dir.pwd
|
796
|
+
path = nil
|
797
|
+
sout, serr = capture_sio do
|
798
|
+
pushd "d1/d2" do
|
799
|
+
path = Dir.pwd
|
800
|
+
end
|
801
|
+
end
|
802
|
+
ok {path} != nil
|
803
|
+
ok {path} != here
|
804
|
+
ok {Dir.pwd} == here
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
|
809
|
+
topic 'cp()' do
|
810
|
+
|
811
|
+
spec "[!mtuec] echoback copy command and arguments." do
|
812
|
+
sout, serr = capture_sio do
|
813
|
+
cp "foo1.txt", "foo9.txt"
|
814
|
+
end
|
815
|
+
ok {sout} == "$ cp foo1.txt foo9.txt\n"
|
816
|
+
#
|
817
|
+
sout, serr = capture_sio do
|
818
|
+
cp :pr, "foo*.txt", to: "d1"
|
819
|
+
end
|
820
|
+
ok {sout} == "$ cp -pr foo*.txt d1\n"
|
821
|
+
end
|
822
|
+
|
823
|
+
case_when "[!u98f8] when `to:` keyword arg not specified..." do
|
824
|
+
spec "[!u39p0] error when number of arguments is not 2." do
|
825
|
+
sout, serr = capture_sio do
|
826
|
+
pr = proc { cp() }
|
827
|
+
ok {pr}.raise?(ArgumentError, "cp: requires two arguments.")
|
828
|
+
pr = proc { cp "foo1.txt" }
|
829
|
+
ok {pr}.raise?(ArgumentError, "cp: requires two arguments.")
|
830
|
+
pr = proc { cp "foo1.txt", "foo2.txt", "foo3.txt" }
|
831
|
+
ok {pr}.raise?(ArgumentError, "cp: too much arguments.")
|
832
|
+
end
|
833
|
+
end
|
834
|
+
spec "[!fux6x] error when source pattern matched to multiple files." do
|
835
|
+
sout, serr = capture_sio do
|
836
|
+
pr = proc { cp "foo?.txt", "blabla.txt" }
|
837
|
+
ok {pr}.raise?(ArgumentError, "cp: foo?.txt: unexpectedly matched to multiple files (foo1.txt, foo2.txt).")
|
838
|
+
end
|
839
|
+
end
|
840
|
+
spec "[!y74ux] error when destination pattern matched to multiple files." do
|
841
|
+
sout, serr = capture_sio do
|
842
|
+
pr = proc { cp "d1/bar.txt", "foo*.txt" }
|
843
|
+
ok {pr}.raise?(ArgumentError, "cp: foo*.txt: unexpectedly matched to multiple files (foo1.txt, foo2.txt).")
|
844
|
+
end
|
845
|
+
end
|
846
|
+
#
|
847
|
+
spec "[!qfidz] error when destination is a directory." do
|
848
|
+
sout, serr = capture_sio do
|
849
|
+
pr = proc { cp "foo1.txt", "d1" }
|
850
|
+
ok {pr}.raise?(ArgumentError, "cp: d1: cannot copy into directory (requires `to: 'd1'` keyword option).")
|
851
|
+
end
|
852
|
+
end
|
853
|
+
spec "[!073so] (cp) error when destination already exists to avoid overwriting it." do
|
854
|
+
sout, serr = capture_sio do
|
855
|
+
pr = proc { cp "foo1.txt", "foo2.txt" }
|
856
|
+
ok {pr}.raise?(ArgumentError, "cp: foo2.txt: file already exists (to overwrite it, call `cp!` instead of `cp`).")
|
857
|
+
end
|
858
|
+
end
|
859
|
+
spec "[!0tw8r] error when source is a directory but '-r' not specified." do
|
860
|
+
sout, serr = capture_sio do
|
861
|
+
pr = proc { cp "d1", "d9" }
|
862
|
+
ok {pr}.raise?(ArgumentError, "cp: d1: is a directory (requires `:-r` option).")
|
863
|
+
end
|
864
|
+
end
|
865
|
+
spec "[!lf6qi] error when target already exists." do
|
866
|
+
sout, serr = capture_sio do
|
867
|
+
dummy_dir("d9")
|
868
|
+
pr = proc { cp :r, "d1", "d9" }
|
869
|
+
ok {pr}.raise?(ArgumentError, "cp: d9: already exists.")
|
870
|
+
end
|
871
|
+
end
|
872
|
+
spec "[!4xxpe] error when source is a special file." do
|
873
|
+
sout, serr = capture_sio do
|
874
|
+
pr = proc { cp :r, "/dev/null", "d9" }
|
875
|
+
ok {pr}.raise?(ArgumentError, "cp: /dev/null: cannot copy special file.")
|
876
|
+
end
|
877
|
+
end
|
878
|
+
spec "[!lr2bj] error when source file not found and '-f' option not specified." do
|
879
|
+
sout, serr = capture_sio do
|
880
|
+
pr = proc { cp "blabla.txt", "blabla2.txt" }
|
881
|
+
ok {pr}.raise?(ArgumentError, "cp: blabla.txt: not found.")
|
882
|
+
end
|
883
|
+
end
|
884
|
+
spec "[!urh40] do nothing if source file not found and '-f' option specified." do
|
885
|
+
sout, serr = capture_sio do
|
886
|
+
cp :f, "blabla.txt", "blabla2.txt"
|
887
|
+
ok {"blabla2.txt"}.not_exist?
|
888
|
+
cp :f, "bla*.txt", "blabla2.txt"
|
889
|
+
ok {"blabla2.txt"}.not_exist?
|
890
|
+
end
|
891
|
+
end
|
892
|
+
spec "[!kqgdl] copy a directory recursively if '-r' option specified." do
|
893
|
+
sout, serr = capture_sio do
|
894
|
+
ok {"d9"}.not_exist?
|
895
|
+
cp :r, "d1", "d9"
|
896
|
+
ok {"d9"}.dir_exist?
|
897
|
+
ok {"d9/bar.txt"}.file_exist?
|
898
|
+
ok {"d9/d2/baz.txt"}.file_exist?
|
899
|
+
#
|
900
|
+
cp :r, "foo1.txt", "blabla.txt"
|
901
|
+
ok {"blabla.txt"}.file_exist?
|
902
|
+
end
|
903
|
+
end
|
904
|
+
spec "[!ko4he] copy a file into new file if '-r' option not specifieid." do
|
905
|
+
sout, serr = capture_sio do
|
906
|
+
cp "foo1.txt", "blabla.txt"
|
907
|
+
ok {"blabla.txt"}.file_exist?
|
908
|
+
end
|
909
|
+
end
|
910
|
+
spec "[!lac46] keeps file mtime if '-p' option specified." do
|
911
|
+
sout, serr = capture_sio do
|
912
|
+
ctime1 = File.ctime("d1/bar.txt")
|
913
|
+
mtime1 = File.mtime("d1/bar.txt")
|
914
|
+
atime1 = File.atime("d1/bar.txt")
|
915
|
+
#mtime2 = mtime1 - 900
|
916
|
+
#atime2 = atime1 - 600
|
917
|
+
mtime2 = (x = mtime1 - 900; Time.new(x.year, x.month, x.day, x.hour, x.min, x.sec))
|
918
|
+
atime2 = (x = atime1 - 600; Time.new(x.year, x.month, x.day, x.hour, x.min, x.sec))
|
919
|
+
#
|
920
|
+
File.utime(atime2, mtime2, "d1/bar.txt")
|
921
|
+
cp :p, "d1/bar.txt", "blabla.txt"
|
922
|
+
ok {File.atime("blabla.txt")} != atime1
|
923
|
+
ok {File.atime("blabla.txt")} == atime2 # !!!
|
924
|
+
ok {File.mtime("blabla.txt")} != mtime1
|
925
|
+
ok {File.mtime("blabla.txt")} == mtime2 # !!!
|
926
|
+
ok {File.ctime("blabla.txt")} != ctime1
|
927
|
+
#
|
928
|
+
cp :pr, "d1", "d9"
|
929
|
+
ok {File.atime("d9/bar.txt")} != atime1
|
930
|
+
ok {File.atime("d9/bar.txt")} == atime2 # !!!
|
931
|
+
ok {File.mtime("d9/bar.txt")} != mtime1
|
932
|
+
ok {File.mtime("d9/bar.txt")} == mtime2 # !!!
|
933
|
+
ok {File.ctime("d9/bar.txt")} != ctime1
|
934
|
+
end
|
935
|
+
end
|
936
|
+
spec "[!d49vw] not keep file mtime if '-p' option not specified." do
|
937
|
+
sout, serr = capture_sio do
|
938
|
+
ctime1 = File.ctime("d1/bar.txt")
|
939
|
+
mtime1 = File.mtime("d1/bar.txt")
|
940
|
+
atime1 = File.atime("d1/bar.txt")
|
941
|
+
#mtime2 = mtime1 - 900
|
942
|
+
#atime2 = atime1 - 600
|
943
|
+
mtime2 = (x = mtime1 - 900; Time.new(x.year, x.month, x.day, x.hour, x.min, x.sec))
|
944
|
+
atime2 = (x = atime1 - 600; Time.new(x.year, x.month, x.day, x.hour, x.min, x.sec))
|
945
|
+
#
|
946
|
+
File.utime(atime2, mtime2, "d1/bar.txt")
|
947
|
+
cp "d1/bar.txt", "blabla.txt"
|
948
|
+
ok {File.atime("blabla.txt")} != atime1
|
949
|
+
ok {File.atime("blabla.txt")} != atime2
|
950
|
+
ok {File.mtime("blabla.txt")} != mtime1
|
951
|
+
ok {File.mtime("blabla.txt")} != mtime2 # !!!
|
952
|
+
ok {File.ctime("blabla.txt")} != ctime1
|
953
|
+
#
|
954
|
+
cp :r, "d1", "d9"
|
955
|
+
ok {File.atime("d9/bar.txt")} != atime1
|
956
|
+
ok {File.atime("d9/bar.txt")} != atime2
|
957
|
+
ok {File.mtime("d9/bar.txt")} != mtime1
|
958
|
+
ok {File.mtime("d9/bar.txt")} != mtime2 # !!!
|
959
|
+
ok {File.ctime("d9/bar.txt")} != ctime1
|
960
|
+
end
|
961
|
+
end
|
962
|
+
spec "[!ubthp] creates hard link instead of copy if '-l' option specified." do
|
963
|
+
sout, serr = capture_sio do
|
964
|
+
cp "foo1.txt", "foo8.txt"
|
965
|
+
ok {File.identical?("foo1.txt", "foo8.txt")} == false
|
966
|
+
cp :l, "foo1.txt", "foo9.txt"
|
967
|
+
ok {File.identical?("foo1.txt", "foo9.txt")} == true
|
968
|
+
end
|
969
|
+
end
|
970
|
+
spec "[!yu51t] error when copying supecial files such as character device." do
|
971
|
+
sout, serr = capture_sio do
|
972
|
+
pr = proc { cp "/dev/null", "null" }
|
973
|
+
ok {pr}.raise?(ArgumentError, "cp: /dev/null: cannot copy special file.")
|
974
|
+
end
|
975
|
+
end
|
976
|
+
end
|
977
|
+
|
978
|
+
case_else "[!z8xce] when `to:` keyword arg specified..." do
|
979
|
+
spec "[!ms2sv] error when destination directory not exist." do
|
980
|
+
sout, serr = capture_sio do
|
981
|
+
pr = proc { cp "foo?.txt", to: "dir9" }
|
982
|
+
ok {pr}.raise?(ArgumentError, "cp: dir9: directory not found.")
|
983
|
+
end
|
984
|
+
end
|
985
|
+
spec "[!q9da3] error when destination pattern matched to multiple filenames." do
|
986
|
+
sout, serr = capture_sio do
|
987
|
+
pr = proc { cp "d1", to: "foo?.txt" }
|
988
|
+
ok {pr}.raise?(ArgumentError, "cp: foo?.txt: unexpectedly matched to multiple filenames (foo1.txt, foo2.txt).")
|
989
|
+
end
|
990
|
+
end
|
991
|
+
spec "[!lg3uz] error when destination is not a directory." do
|
992
|
+
sout, serr = capture_sio do
|
993
|
+
pr = proc { cp "d1", to: "foo1.txt" }
|
994
|
+
ok {pr}.raise?(ArgumentError, "cp: foo1.txt: Not a directory.")
|
995
|
+
end
|
996
|
+
end
|
997
|
+
spec "[!slavo] error when file not exist but '-f' option not specified." do
|
998
|
+
sout, serr = capture_sio do
|
999
|
+
pr = proc { cp "blabla", to: "d1" }
|
1000
|
+
ok {pr}.raise?(ArgumentError, "cp: blabla: file or directory not found (add '-f' option to ignore missing files).")
|
1001
|
+
end
|
1002
|
+
end
|
1003
|
+
spec "[!1ceaf] (cp) error when target file or directory already exists." do
|
1004
|
+
sout, serr = capture_sio do
|
1005
|
+
dummy_file("d1/foo1.txt", "tmp")
|
1006
|
+
pr = proc { cp "foo?.txt", to: "d1" }
|
1007
|
+
ok {pr}.raise?(ArgumentError, "cp: d1/foo1.txt: file or directory already exists (to overwrite it, call 'cp!' instead of 'cp').")
|
1008
|
+
end
|
1009
|
+
end
|
1010
|
+
#
|
1011
|
+
spec "[!bi897] error when copying directory but '-r' option not specified." do
|
1012
|
+
sout, serr = capture_sio do
|
1013
|
+
dummy_dir("d9")
|
1014
|
+
pr = proc { cp "d1", to: "d9" }
|
1015
|
+
ok {pr}.raise?(ArgumentError, "cp: d1: cannot copy directory (add '-r' option to copy it).")
|
1016
|
+
end
|
1017
|
+
end
|
1018
|
+
spec "[!654d2] copy files recursively if '-r' option specified." do
|
1019
|
+
sout, serr = capture_sio do
|
1020
|
+
dummy_dir("d9")
|
1021
|
+
ok {"d9"}.dir_exist?
|
1022
|
+
cp :r, "foo*.txt", "d1", to: "d9"
|
1023
|
+
ok {"d9/foo1.txt"}.file_exist?
|
1024
|
+
ok {"d9/foo2.txt"}.file_exist?
|
1025
|
+
ok {"d9/d1/bar.txt"}.file_exist?
|
1026
|
+
ok {"d9/d1/d2/baz.txt"}.file_exist?
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
spec "[!i5g8r] copy files non-recursively if '-r' option not specified." do
|
1030
|
+
sout, serr = capture_sio do
|
1031
|
+
dummy_dir("d9")
|
1032
|
+
ok {"d9"}.dir_exist?
|
1033
|
+
cp "foo*.txt", "d1/**/*.txt", to: "d9"
|
1034
|
+
ok {"d9/foo1.txt"}.file_exist?
|
1035
|
+
ok {"d9/foo2.txt"}.file_exist?
|
1036
|
+
ok {"d9/bar.txt"}.file_exist?
|
1037
|
+
ok {"d9/baz.txt"}.file_exist?
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
spec "[!k8gyx] keeps file timestamp (mtime) if '-p' option specified." do
|
1041
|
+
sout, serr = capture_sio do
|
1042
|
+
ctime1 = File.ctime("d1/bar.txt")
|
1043
|
+
mtime1 = File.mtime("d1/bar.txt")
|
1044
|
+
atime1 = File.atime("d1/bar.txt")
|
1045
|
+
#mtime2 = mtime1 - 30
|
1046
|
+
#atime2 = atime1 - 90
|
1047
|
+
mtime2 = (x = mtime1 - 900; Time.new(x.year, x.month, x.day, x.hour, x.min, x.sec))
|
1048
|
+
atime2 = (x = atime1 - 600; Time.new(x.year, x.month, x.day, x.hour, x.min, x.sec))
|
1049
|
+
File.utime(atime2, mtime2, "d1/bar.txt")
|
1050
|
+
#
|
1051
|
+
dummy_dir("d9")
|
1052
|
+
cp :p, "foo*.txt", "d1/**/*.txt", to: "d9"
|
1053
|
+
ok {File.ctime("d9/bar.txt")} != ctime1
|
1054
|
+
ok {File.mtime("d9/bar.txt")} != mtime1
|
1055
|
+
ok {File.mtime("d9/bar.txt")} == mtime2 # !!!
|
1056
|
+
ok {File.atime("d9/bar.txt")} != atime1
|
1057
|
+
ok {File.atime("d9/bar.txt")} == atime2 # !!!
|
1058
|
+
#
|
1059
|
+
cp :pr, "d1", to: "d9"
|
1060
|
+
ok {File.ctime("d9/d1/bar.txt")} != ctime1
|
1061
|
+
ok {File.mtime("d9/d1/bar.txt")} != mtime1
|
1062
|
+
ok {File.mtime("d9/d1/bar.txt")} == mtime2 # !!!
|
1063
|
+
ok {File.atime("d9/d1/bar.txt")} != atime1
|
1064
|
+
ok {File.atime("d9/d1/bar.txt")} == atime2 # !!!
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
spec "[!zoun9] not keep file timestamp (mtime) if '-p' option not specified." do
|
1068
|
+
sout, serr = capture_sio do
|
1069
|
+
ctime1 = File.ctime("d1/bar.txt")
|
1070
|
+
mtime1 = File.mtime("d1/bar.txt")
|
1071
|
+
atime1 = File.atime("d1/bar.txt")
|
1072
|
+
mtime2 = mtime1 - 30
|
1073
|
+
atime2 = atime1 - 90
|
1074
|
+
File.utime(atime2, mtime2, "d1/bar.txt")
|
1075
|
+
#
|
1076
|
+
dummy_dir("d9")
|
1077
|
+
cp "foo*.txt", "d1/**/*.txt", to: "d9"
|
1078
|
+
ok {File.ctime("d9/bar.txt")} != ctime1
|
1079
|
+
ok {File.mtime("d9/bar.txt")} != mtime1
|
1080
|
+
ok {File.mtime("d9/bar.txt")} != mtime2 # !!!
|
1081
|
+
ok {File.atime("d9/bar.txt")} != atime1
|
1082
|
+
ok {File.atime("d9/bar.txt")} != atime2
|
1083
|
+
#
|
1084
|
+
cp :r, "d1", to: "d9"
|
1085
|
+
ok {File.ctime("d9/d1/bar.txt")} != ctime1
|
1086
|
+
ok {File.mtime("d9/d1/bar.txt")} != mtime1
|
1087
|
+
ok {File.mtime("d9/d1/bar.txt")} != mtime2 # !!!
|
1088
|
+
ok {File.atime("d9/d1/bar.txt")} != atime1
|
1089
|
+
ok {File.atime("d9/d1/bar.txt")} != atime2
|
1090
|
+
end
|
1091
|
+
end
|
1092
|
+
spec "[!p7ah8] creates hard link instead of copy if '-l' option specified." do
|
1093
|
+
sout, serr = capture_sio do
|
1094
|
+
cp :l, "foo*.txt", to: "d1"
|
1095
|
+
ok {File.identical?("foo1.txt", "d1/foo1.txt")} == true
|
1096
|
+
ok {File.identical?("foo2.txt", "d1/foo2.txt")} == true
|
1097
|
+
end
|
1098
|
+
end
|
1099
|
+
spec "[!e90ii] error when copying supecial files such as character device." do
|
1100
|
+
sout, serr = capture_sio do
|
1101
|
+
pr = proc { cp "/dev/null", to: "d1" }
|
1102
|
+
ok {pr}.raise?(ArgumentError, "cp: /dev/null: cannot copy characterSpecial file.")
|
1103
|
+
end
|
1104
|
+
end
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
|
1110
|
+
topic 'cp!()' do
|
1111
|
+
spec "[!cpr7l] (cp!) overwrites existing destination file." do
|
1112
|
+
sout, serr = capture_sio do
|
1113
|
+
dummy_file("foo9.txt", "")
|
1114
|
+
ok {"foo9.txt"}.file_exist?
|
1115
|
+
cp! "foo1.txt", "foo9.txt"
|
1116
|
+
ok {"foo9.txt"}.file_exist?
|
1117
|
+
ok {File.read("foo9.txt")} == File.read("foo1.txt")
|
1118
|
+
#
|
1119
|
+
pr = proc { cp "foo1.txt", "foo9.txt" }
|
1120
|
+
ok {pr}.raise?(ArgumentError, "cp: foo9.txt: file already exists (to overwrite it, call `cp!` instead of `cp`).")
|
1121
|
+
end
|
1122
|
+
end
|
1123
|
+
spec "[!melhx] (cp!) overwrites existing files." do
|
1124
|
+
sout, serr = capture_sio do
|
1125
|
+
dummy_dir("d9")
|
1126
|
+
dummy_file("d9/foo1.txt", "")
|
1127
|
+
ok {"d9/foo1.txt"}.file_exist?
|
1128
|
+
cp! "foo1.txt", to: "d9"
|
1129
|
+
ok {"d9/foo1.txt"}.file_exist?
|
1130
|
+
ok {File.read("d9/foo1.txt")} == File.read("foo1.txt")
|
1131
|
+
#
|
1132
|
+
pr = proc { cp "foo1.txt", to: "d9" }
|
1133
|
+
ok {pr}.raise?(ArgumentError, "cp: d9/foo1.txt: file or directory already exists (to overwrite it, call 'cp!' instead of 'cp').")
|
1134
|
+
end
|
1135
|
+
end
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
|
1139
|
+
topic 'mv()' do
|
1140
|
+
|
1141
|
+
spec "[!ajm59] echoback command and arguments." do
|
1142
|
+
sout, serr = capture_sio do
|
1143
|
+
mv "foo1.txt", "foo9.txt"
|
1144
|
+
mv "foo2.txt", to: "d1"
|
1145
|
+
end
|
1146
|
+
ok {sout} == ("$ mv foo1.txt foo9.txt\n"\
|
1147
|
+
"$ mv foo2.txt d1\n")
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
case_when "[!g732t] when `to:` keyword argument not specified..." do
|
1151
|
+
spec "[!0f106] error when number of arguments is not 2." do
|
1152
|
+
sout, serr = capture_sio do
|
1153
|
+
pr = proc { mv() }
|
1154
|
+
ok {pr}.raise?(ArgumentError, "mv: requires two arguments.")
|
1155
|
+
pr = proc { mv "foo1.txt" }
|
1156
|
+
ok {pr}.raise?(ArgumentError, "mv: requires two arguments.")
|
1157
|
+
pr = proc { mv "foo1.txt", "foo2.txt", "foo3.txt" }
|
1158
|
+
ok {pr}.raise?(ArgumentError, "mv: too much arguments.")
|
1159
|
+
end
|
1160
|
+
end
|
1161
|
+
spec "[!xsti2] error when source pattern matched to multiple files." do
|
1162
|
+
sout, serr = capture_sio do
|
1163
|
+
pr = proc { mv "foo?.txt", "blabla.txt" }
|
1164
|
+
ok {pr}.raise?(ArgumentError, "mv: foo?.txt: unexpectedly matched to multiple files (foo1.txt, foo2.txt).")
|
1165
|
+
end
|
1166
|
+
end
|
1167
|
+
spec "[!4wam3] error when destination pattern matched to multiple files." do
|
1168
|
+
sout, serr = capture_sio do
|
1169
|
+
pr = proc { mv "d1/bar.txt", "foo*.txt" }
|
1170
|
+
ok {pr}.raise?(ArgumentError, "mv: foo*.txt: unexpectedly matched to multiple files (foo1.txt, foo2.txt).")
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
#
|
1174
|
+
spec "[!ude1j] cannot move file into existing directory." do
|
1175
|
+
sout, serr = capture_sio do
|
1176
|
+
pr = proc { mv "foo1.txt", "d1" }
|
1177
|
+
ok {pr}.raise?(ArgumentError, "mv: cannot move file 'foo1.txt' into directory 'd1' without 'to:' keyword option.")
|
1178
|
+
end
|
1179
|
+
end
|
1180
|
+
spec "[!2aws0] cannt rename directory into existing file or directory." do
|
1181
|
+
sout, serr = capture_sio do
|
1182
|
+
pr = proc { mv "d1", "foo1.txt" }
|
1183
|
+
ok {pr}.raise?(ArgumentError, "mv: cannot rename directory 'd1' to existing file or directory.")
|
1184
|
+
end
|
1185
|
+
end
|
1186
|
+
spec "[!3fbpu] (mv) error when destination file already exists." do
|
1187
|
+
sout, serr = capture_sio do
|
1188
|
+
pr = proc { mv "foo1.txt", "foo2.txt" }
|
1189
|
+
ok {pr}.raise?(ArgumentError, "mv: foo2.txt: already exists (to overwrite it, call `mv!` instead of `mv`).")
|
1190
|
+
end
|
1191
|
+
end
|
1192
|
+
spec "[!397kn] do nothing when file or directory not found but '-f' option specified." do
|
1193
|
+
sout, serr = capture_sio do
|
1194
|
+
mv :f, "blabla.txt", "blabla2.txt"
|
1195
|
+
ok {"blabla2.txt"}.not_exist?
|
1196
|
+
end
|
1197
|
+
end
|
1198
|
+
spec "[!1z89i] error when source file or directory not found." do
|
1199
|
+
sout, serr = capture_sio do
|
1200
|
+
pr = proc { mv "blabla.txt", "blabla2.txt" }
|
1201
|
+
ok {pr}.raise?(ArgumentError, "mv: blabla.txt: not found.")
|
1202
|
+
end
|
1203
|
+
end
|
1204
|
+
spec "[!9eqt3] rename file or directory." do
|
1205
|
+
sout, serr = capture_sio do
|
1206
|
+
s = File.read("foo1.txt")
|
1207
|
+
mv "foo1.txt", "blabla.txt"
|
1208
|
+
ok {"foo1.txt"}.not_exist?
|
1209
|
+
ok {"blabla.txt"}.file_exist?
|
1210
|
+
ok {File.read("blabla.txt")} == s
|
1211
|
+
#
|
1212
|
+
mv "d1", "d9"
|
1213
|
+
ok {"d1"}.not_exist?
|
1214
|
+
ok {"d9"}.dir_exist?
|
1215
|
+
end
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
|
1219
|
+
case_else "[!iu87y] when `to:` keyword argument specified..." do
|
1220
|
+
spec "[!wf6pc] error when destination directory not exist." do
|
1221
|
+
sout, serr = capture_sio do
|
1222
|
+
pr = proc { mv "foo?.txt", to: "dir9" }
|
1223
|
+
ok {pr}.raise?(ArgumentError, "mv: dir9: directory not found.")
|
1224
|
+
end
|
1225
|
+
end
|
1226
|
+
spec "[!8v4dn] error when destination pattern matched to multiple filenames." do
|
1227
|
+
sout, serr = capture_sio do
|
1228
|
+
pr = proc { mv "d1", to: "foo?.txt" }
|
1229
|
+
ok {pr}.raise?(ArgumentError, "mv: foo?.txt: unexpectedly matched to multiple filenames (foo1.txt, foo2.txt).")
|
1230
|
+
end
|
1231
|
+
end
|
1232
|
+
spec "[!ppr6n] error when destination is not a directory." do
|
1233
|
+
sout, serr = capture_sio do
|
1234
|
+
pr = proc { mv "d1", to: "foo1.txt" }
|
1235
|
+
ok {pr}.raise?(ArgumentError, "mv: foo1.txt: Not a directory.")
|
1236
|
+
end
|
1237
|
+
end
|
1238
|
+
spec "[!bjqwi] error when file not exist but '-f' option not specified." do
|
1239
|
+
sout, serr = capture_sio do
|
1240
|
+
pr = proc { mv "blabla", to: "d1" }
|
1241
|
+
ok {pr}.raise?(ArgumentError, "mv: blabla: file or directory not found (add '-f' option to ignore missing files).")
|
1242
|
+
end
|
1243
|
+
end
|
1244
|
+
spec "[!k21ns] (mv) error when target file or directory already exists." do
|
1245
|
+
sout, serr = capture_sio do
|
1246
|
+
dummy_file("d1/foo1.txt", "tmp")
|
1247
|
+
pr = proc { mv "foo?.txt", to: "d1" }
|
1248
|
+
ok {pr}.raise?(ArgumentError, "mv: d1/foo1.txt: file or directory already exists (to overwrite it, call 'mv!' instead of 'mv').")
|
1249
|
+
end
|
1250
|
+
end
|
1251
|
+
#
|
1252
|
+
spec "[!ri2ia] move files into existing directory." do
|
1253
|
+
sout, serr = capture_sio do
|
1254
|
+
mv "foo?.txt", to: "d1/d2"
|
1255
|
+
ok {"foo1.txt"}.not_exist?
|
1256
|
+
ok {"foo2.txt"}.not_exist?
|
1257
|
+
ok {"d1/d2/foo1.txt"}.file_exist?
|
1258
|
+
ok {"d1/d2/foo2.txt"}.file_exist?
|
1259
|
+
end
|
1260
|
+
end
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
|
1266
|
+
topic 'mv!()' do
|
1267
|
+
spec "[!zpojx] (mv!) overwrites existing files." do
|
1268
|
+
sout, serr = capture_sio do
|
1269
|
+
pr = proc { mv "foo1.txt", "foo2.txt" }
|
1270
|
+
ok {pr}.raise?(ArgumentError, "mv: foo2.txt: already exists (to overwrite it, call `mv!` instead of `mv`).")
|
1271
|
+
#
|
1272
|
+
s = File.read("foo2.txt")
|
1273
|
+
mv! "foo1.txt", "foo2.txt"
|
1274
|
+
ok {"foo1.txt"}.not_exist?
|
1275
|
+
ok {"foo2.txt"}.file_exist?
|
1276
|
+
ok {File.read("foo2.txt")} != s
|
1277
|
+
end
|
1278
|
+
end
|
1279
|
+
spec "[!vcaf5] (mv!) overwrites existing files." do
|
1280
|
+
sout, serr = capture_sio do
|
1281
|
+
mv "foo1.txt", to: "d1"
|
1282
|
+
ok {"d1/foo1.txt"}.file_exist?
|
1283
|
+
#
|
1284
|
+
mv "d1/foo1.txt", "d1/foo2.txt"
|
1285
|
+
pr = proc { mv "foo2.txt", to: "d1" }
|
1286
|
+
ok {pr}.raise?(ArgumentError, "mv: d1/foo2.txt: file or directory already exists (to overwrite it, call 'mv!' instead of 'mv').")
|
1287
|
+
end
|
1288
|
+
end
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
|
1292
|
+
topic 'rm()' do
|
1293
|
+
spec "[!bikrs] echoback command and arguments." do
|
1294
|
+
sout, serr = capture_sio do
|
1295
|
+
rm "foo*.txt"
|
1296
|
+
end
|
1297
|
+
ok {sout} == "$ rm foo*.txt\n"
|
1298
|
+
end
|
1299
|
+
spec "[!va1j0] error when file not exist but '-f' option not specified." do
|
1300
|
+
sout, serr = capture_sio do
|
1301
|
+
pr = proc { rm "foo*.txt", "blabla*.txt" }
|
1302
|
+
ok {pr}.raise?(ArgumentError, "rm: blabla*.txt: file or directory not found (add '-f' option to ignore missing files).")
|
1303
|
+
ok {"foo1.txt"}.file_exist?
|
1304
|
+
#
|
1305
|
+
end
|
1306
|
+
end
|
1307
|
+
spec "[!t6vhx] ignores missing files if '-f' option specified." do
|
1308
|
+
sout, serr = capture_sio do
|
1309
|
+
rm :f, "foo*.txt", "blabla*.txt"
|
1310
|
+
ok {"foo1.txt"}.not_exist?
|
1311
|
+
end
|
1312
|
+
end
|
1313
|
+
spec "[!o92yi] cannot remove directory unless '-r' option specified." do
|
1314
|
+
sout, serr = capture_sio do
|
1315
|
+
pr = proc { rm "d1" }
|
1316
|
+
ok {pr}.raise?(ArgumentError, "rm: d1: cannot remove directory (add '-r' option to remove it).")
|
1317
|
+
end
|
1318
|
+
end
|
1319
|
+
spec "[!srx8w] remove directories recursively if '-r' option specified." do
|
1320
|
+
sout, serr = capture_sio do
|
1321
|
+
ok {"d1"}.dir_exist?
|
1322
|
+
rm :r, "d1"
|
1323
|
+
ok {"d1"}.not_exist?
|
1324
|
+
end
|
1325
|
+
end
|
1326
|
+
spec "[!mdgjc] remove files if '-r' option not specified." do
|
1327
|
+
sout, serr = capture_sio do
|
1328
|
+
rm "foo*.txt"
|
1329
|
+
ok {"foo1.txt"}.not_exist?
|
1330
|
+
ok {"foo2.txt"}.not_exist?
|
1331
|
+
end
|
1332
|
+
end
|
1333
|
+
end
|
1334
|
+
|
1335
|
+
|
1336
|
+
topic 'mkdir()' do
|
1337
|
+
spec "[!wd7rm] error when mode is invalid." do
|
1338
|
+
sout, serr = capture_sio do
|
1339
|
+
pr = proc { mkdir :m, "a+x" }
|
1340
|
+
ok {pr}.raise?(ArgumentError, "mkdir: a+x: '-m' option doesn't support this style mode (use '0755' tyle instead).")
|
1341
|
+
#
|
1342
|
+
pr = proc { mkdir :m, "+x" }
|
1343
|
+
ok {pr}.raise?(ArgumentError, "mkdir: +x: invalid mode.")
|
1344
|
+
end
|
1345
|
+
end
|
1346
|
+
spec "[!xusor] raises error when argument not specified." do
|
1347
|
+
sout, serr = capture_sio do
|
1348
|
+
pr = proc { mkdir() }
|
1349
|
+
ok {pr}.raise?(ArgumentError, "mkdir: argument required.")
|
1350
|
+
end
|
1351
|
+
end
|
1352
|
+
spec "[!51pmg] error when directory already exists but '-p' option not specified." do
|
1353
|
+
sout, serr = capture_sio do
|
1354
|
+
pr = proc { mkdir "d1" }
|
1355
|
+
ok {pr}.raise?(ArgumentError, "mkdir: d1: directory already exists.")
|
1356
|
+
end
|
1357
|
+
end
|
1358
|
+
spec "[!pydy1] ignores existing directories if '-p' option specified." do
|
1359
|
+
sout, serr = capture_sio do
|
1360
|
+
ok {"d1"}.dir_exist?
|
1361
|
+
mkdir :p, "d1"
|
1362
|
+
ok {"d1"}.dir_exist?
|
1363
|
+
end
|
1364
|
+
end
|
1365
|
+
spec "[!om8a6] error when file already exists." do
|
1366
|
+
sout, serr = capture_sio do
|
1367
|
+
pr = proc { mkdir "foo1.txt" }
|
1368
|
+
ok {pr}.raise?(ArgumentError, "mkdir: foo1.txt: file exists.")
|
1369
|
+
end
|
1370
|
+
end
|
1371
|
+
spec "[!xx7mv] error when parent directory not exist but '-p' option not specified." do
|
1372
|
+
sout, serr = capture_sio do
|
1373
|
+
pr = proc { mkdir "d1/a/b" }
|
1374
|
+
ok {pr}.raise?(ArgumentError, "mkdir: d1/a/b: parent directory not exists (add '-p' to create it).")
|
1375
|
+
end
|
1376
|
+
end
|
1377
|
+
spec "[!jc8hm] '-m' option specifies mode of new directories." do
|
1378
|
+
sout, serr = capture_sio do
|
1379
|
+
ok {"d9"}.not_exist?
|
1380
|
+
mkdir :m, 0750, "d9"
|
1381
|
+
ok {"d9"}.dir_exist?
|
1382
|
+
ok {File.stat("d9").mode & 0777} == 0750
|
1383
|
+
#
|
1384
|
+
mkdir :pm, 0705, "d9/a/b"
|
1385
|
+
ok {"d9/a/b"}.dir_exist?
|
1386
|
+
ok {File.stat("d9/a/b").mode & 0777} == 0705
|
1387
|
+
end
|
1388
|
+
end
|
1389
|
+
spec "[!0zeu3] create intermediate path if '-p' option specified." do
|
1390
|
+
sout, serr = capture_sio do
|
1391
|
+
ok {"d1/a/b"}.not_exist?
|
1392
|
+
mkdir :p, "d1/a/b"
|
1393
|
+
ok {"d1/a/b"}.dir_exist?
|
1394
|
+
#
|
1395
|
+
ok {"d9/a/b"}.not_exist?
|
1396
|
+
mkdir :p, "d9/a/b"
|
1397
|
+
ok {"d9/a/b"}.dir_exist?
|
1398
|
+
end
|
1399
|
+
end
|
1400
|
+
spec "[!l0pr8] create directories if '-p' option not specified." do
|
1401
|
+
sout, serr = capture_sio do
|
1402
|
+
mkdir :p, "aa", "bb", "cc"
|
1403
|
+
ok {"aa"}.dir_exist?
|
1404
|
+
ok {"bb"}.dir_exist?
|
1405
|
+
ok {"cc"}.dir_exist?
|
1406
|
+
end
|
1407
|
+
end
|
1408
|
+
end
|
1409
|
+
|
1410
|
+
|
1411
|
+
topic 'rmdir()' do
|
1412
|
+
spec "[!bqhdd] error when argument not specified." do
|
1413
|
+
sout, serr = capture_sio do
|
1414
|
+
pr = proc { rmdir() }
|
1415
|
+
ok {pr}.raise?(ArgumentError, "rmdir: argument required.")
|
1416
|
+
end
|
1417
|
+
end
|
1418
|
+
spec "[!o1k3g] error when directory not exist." do
|
1419
|
+
sout, serr = capture_sio do
|
1420
|
+
pr = proc { rmdir "d9" }
|
1421
|
+
ok {pr}.raise?(ArgumentError, "rmdir: d9: No such file or directory.")
|
1422
|
+
end
|
1423
|
+
end
|
1424
|
+
spec "[!ch5rq] error when directory is a symbolic link." do
|
1425
|
+
sout, serr = capture_sio do
|
1426
|
+
File.symlink("foo1.txt", "foo1.lnk")
|
1427
|
+
pr = proc { rmdir "foo1.lnk" }
|
1428
|
+
ok {pr}.raise?(ArgumentError, "rmdir: foo1.lnk: Not a directory.")
|
1429
|
+
end
|
1430
|
+
end
|
1431
|
+
spec "[!igfti] error when directory is not empty." do
|
1432
|
+
sout, serr = capture_sio do
|
1433
|
+
pr = proc { rmdir "d1" }
|
1434
|
+
#ok {pr}.raise?(Errno::ENOTEMPTY, "Directory not empty @ dir_s_rmdir - d9")
|
1435
|
+
ok {pr}.raise?(ArgumentError, "rmdir: d1: Directory not empty.")
|
1436
|
+
end
|
1437
|
+
end
|
1438
|
+
spec "[!qnnqy] error when argument is not a directory." do
|
1439
|
+
sout, serr = capture_sio do
|
1440
|
+
pr = proc { rmdir "foo1.txt" }
|
1441
|
+
ok {pr}.raise?(ArgumentError, "rmdir: foo1.txt: Not a directory.")
|
1442
|
+
end
|
1443
|
+
end
|
1444
|
+
spec "[!jgmw7] remove empty directories." do
|
1445
|
+
sout, serr = capture_sio do
|
1446
|
+
dummy_dir "d9/a/b"
|
1447
|
+
ok {"d9/a/b"}.dir_exist?
|
1448
|
+
rmdir "d9/a/b"
|
1449
|
+
ok {"d9/a/b"}.not_exist?
|
1450
|
+
rmdir "d9/a"
|
1451
|
+
ok {"d9/a"}.not_exist?
|
1452
|
+
end
|
1453
|
+
end
|
1454
|
+
end
|
1455
|
+
|
1456
|
+
|
1457
|
+
topic 'ln()' do
|
1458
|
+
spec "[!ycp6e] echobacks command and arguments." do
|
1459
|
+
sout, serr = capture_sio do
|
1460
|
+
ln "foo1.txt", "foo8.txt"
|
1461
|
+
ln :s, "foo2.txt", "foo9.txt"
|
1462
|
+
end
|
1463
|
+
ok {sout} == ("$ ln -n foo1.txt foo8.txt\n"\
|
1464
|
+
"$ ln -sn foo2.txt foo9.txt\n")
|
1465
|
+
end
|
1466
|
+
spec "[!umk6m] keyword arg `to: xx` is echobacked as `-t xx`." do
|
1467
|
+
sout, serr = capture_sio do
|
1468
|
+
ln "foo*.txt", to: "d1"
|
1469
|
+
end
|
1470
|
+
ok {sout} == ("$ ln -t d1 -n foo*.txt\n")
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
case_when "[!qtbp4] when `to:` keyword argument not specified..." do
|
1474
|
+
spec "[!n1zpi] error when number of arguments is not 2." do
|
1475
|
+
sout, serr = capture_sio do
|
1476
|
+
pr = proc { ln() }
|
1477
|
+
ok {pr}.raise?(ArgumentError, "ln: requires two arguments.")
|
1478
|
+
pr = proc { ln "foo1.txt" }
|
1479
|
+
ok {pr}.raise?(ArgumentError, "ln: requires two arguments.")
|
1480
|
+
end
|
1481
|
+
end
|
1482
|
+
spec "[!2rxqo] error when source pattern matched to multiple files." do
|
1483
|
+
sout, serr = capture_sio do
|
1484
|
+
pr = proc { ln "foo*.txt", "bar.txt" }
|
1485
|
+
ok {pr}.raise?(ArgumentError, "ln: foo*.txt: unexpectedly matched to multiple files (foo1.txt, foo2.txt).")
|
1486
|
+
end
|
1487
|
+
end
|
1488
|
+
spec "[!ysxdq] error when destination pattern matched to multiple files." do
|
1489
|
+
sout, serr = capture_sio do
|
1490
|
+
pr = proc { ln "d9/bar.txt", "foo*.txt" }
|
1491
|
+
ok {pr}.raise?(ArgumentError, "ln: foo*.txt: unexpectedly matched to multiple files (foo1.txt, foo2.txt).")
|
1492
|
+
end
|
1493
|
+
end
|
1494
|
+
#
|
1495
|
+
spec "[!4ry8j] (hard link) error when source file not exists." do
|
1496
|
+
sout, serr = capture_sio do
|
1497
|
+
pr = proc { ln "foo8.txt", "foo9.txt" }
|
1498
|
+
ok {pr}.raise?(ArgumentError, "ln: foo8.txt: No such file or directory.")
|
1499
|
+
end
|
1500
|
+
end
|
1501
|
+
spec "[!tf29w] (hard link) error when source is a directory." do
|
1502
|
+
sout, serr = capture_sio do
|
1503
|
+
pr = proc { ln "d1", "d2" }
|
1504
|
+
ok {pr}.raise?(ArgumentError, "ln: d1: Is a directory.")
|
1505
|
+
end
|
1506
|
+
end
|
1507
|
+
spec "[!zmijh] error when destination is a directory without `to:` keyword argument." do
|
1508
|
+
sout, serr = capture_sio do
|
1509
|
+
pr = proc { ln "foo1.txt", "d1" }
|
1510
|
+
ok {pr}.raise?(ArgumentError, "ln: d1: cannot create link under directory without `to:` keyword option.")
|
1511
|
+
end
|
1512
|
+
end
|
1513
|
+
spec "[!nzci0] (ln) error when destination already exists." do
|
1514
|
+
sout, serr = capture_sio do
|
1515
|
+
pr = proc { ln "foo1.txt", "d1" }
|
1516
|
+
ok {pr}.raise?(ArgumentError, "ln: d1: cannot create link under directory without `to:` keyword option.")
|
1517
|
+
pr = proc { ln :s, "foo1.txt", "d1" }
|
1518
|
+
ok {pr}.raise?(ArgumentError, "ln: d1: cannot create link under directory without `to:` keyword option.")
|
1519
|
+
end
|
1520
|
+
end
|
1521
|
+
spec "[!oxjqv] create symbolic link if '-s' option specified." do
|
1522
|
+
sout, serr = capture_sio do
|
1523
|
+
ln :s, "foo1.txt", "foo9.txt"
|
1524
|
+
ok {"foo9.txt"}.file_exist?
|
1525
|
+
ok {"foo9.txt"}.symlink_exist?
|
1526
|
+
ln :s, "d1", "d9"
|
1527
|
+
ok {"d9"}.dir_exist?
|
1528
|
+
ok {"d9"}.symlink_exist?
|
1529
|
+
end
|
1530
|
+
end
|
1531
|
+
spec "[!awig1] (symlink) can create symbolic link to non-existing file." do
|
1532
|
+
sout, serr = capture_sio do
|
1533
|
+
ok {"foo8.txt"}.not_exist?
|
1534
|
+
ln :s, "foo8.txt", "foo9.txt"
|
1535
|
+
ok {"foo9.txt"}.symlink_exist?
|
1536
|
+
end
|
1537
|
+
end
|
1538
|
+
spec "[!5kl3w] (symlink) can create symbolic link to directory." do
|
1539
|
+
sout, serr = capture_sio do
|
1540
|
+
ln :s, "d1", "d9"
|
1541
|
+
ok {"d9"}.symlink_exist?
|
1542
|
+
end
|
1543
|
+
end
|
1544
|
+
spec "[!sb29p] create hard link if '-s' option not specified." do
|
1545
|
+
sout, serr = capture_sio do
|
1546
|
+
ln "foo1.txt", "foo9.txt"
|
1547
|
+
ok {"foo9.txt"}.file_exist?
|
1548
|
+
ok {"foo9.txt"}.NOT.symlink_exist?
|
1549
|
+
end
|
1550
|
+
end
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
case_else "[!5x2wr] when `to:` keyword argument specified..." do
|
1554
|
+
spec "[!5gfxk] error when destination directory not exist." do
|
1555
|
+
sout, serr = capture_sio do
|
1556
|
+
pr = proc { ln "foo*.txt", to: "d9" }
|
1557
|
+
ok {pr}.raise?(ArgumentError, "ln: d9: directory not found.")
|
1558
|
+
end
|
1559
|
+
end
|
1560
|
+
spec "[!euu5d] error when destination pattern matched to multiple filenames." do
|
1561
|
+
sout, serr = capture_sio do
|
1562
|
+
pr = proc { ln "d1/bar.txt", to: "foo*.txt" }
|
1563
|
+
ok {pr}.raise?(ArgumentError, "ln: foo*.txt: unexpectedly matched to multiple filenames (foo1.txt, foo2.txt).")
|
1564
|
+
end
|
1565
|
+
end
|
1566
|
+
spec "[!42nb7] error when destination is not a directory." do
|
1567
|
+
sout, serr = capture_sio do
|
1568
|
+
pr = proc { ln "foo1.txt", to: "foo2.txt" }
|
1569
|
+
ok {pr}.raise?(ArgumentError, "ln: foo2.txt: Not a directory.")
|
1570
|
+
end
|
1571
|
+
end
|
1572
|
+
#
|
1573
|
+
spec "[!x7wh5] (symlink) can create symlink to unexisting file." do
|
1574
|
+
sout, serr = capture_sio do
|
1575
|
+
ln :s, "foo8.txt", to: "d1"
|
1576
|
+
ok {"d1/foo8.txt"}.not_exist?
|
1577
|
+
ok {"d1/foo8.txt"}.symlink_exist?
|
1578
|
+
end
|
1579
|
+
end
|
1580
|
+
spec "[!ml1vm] (hard link) error when source file not exist." do
|
1581
|
+
sout, serr = capture_sio do
|
1582
|
+
pr = proc { ln "foo8.txt", to: "d1" }
|
1583
|
+
ok {pr}.raise?(ArgumentError, "ln: foo8.txt: No such file or directory.")
|
1584
|
+
end
|
1585
|
+
end
|
1586
|
+
#
|
1587
|
+
spec "[!mwukw] (ln) error when target file or directory already exists." do
|
1588
|
+
sout, serr = capture_sio do
|
1589
|
+
dummy_file("d1/foo1.txt", "foo1")
|
1590
|
+
pr = proc { ln "foo*.txt", to: "d1" } # hard link
|
1591
|
+
ok {pr}.raise?(ArgumentError, "ln: d1/foo1.txt: File exists (to overwrite it, call `ln!` instead of `ln`).")
|
1592
|
+
#
|
1593
|
+
pr = proc { ln :s, "foo*.txt", to: "d1" } # symbolic link
|
1594
|
+
ok {pr}.raise?(ArgumentError, "ln: d1/foo1.txt: File exists (to overwrite it, call `ln!` instead of `ln`).")
|
1595
|
+
end
|
1596
|
+
end
|
1597
|
+
spec "[!c8hpp] (hard link) create hard link under directory if '-s' option not specified." do
|
1598
|
+
sout, serr = capture_sio do
|
1599
|
+
ln "foo*.txt", to: "d1"
|
1600
|
+
ok {"d1/foo1.txt"}.file_exist?
|
1601
|
+
ok {"d1/foo2.txt"}.file_exist?
|
1602
|
+
ok {"d1/foo1.txt"}.NOT.symlink_exist?
|
1603
|
+
ok {"d1/foo2.txt"}.NOT.symlink_exist?
|
1604
|
+
end
|
1605
|
+
end
|
1606
|
+
spec "[!9tv9g] (symlik) create symbolic link under directory if '-s' option specified." do
|
1607
|
+
sout, serr = capture_sio do
|
1608
|
+
ln :s, "foo*.txt", to: "d1"
|
1609
|
+
ok {"d1/foo1.txt"}.symlink_exist?
|
1610
|
+
ok {"d1/foo2.txt"}.symlink_exist?
|
1611
|
+
ok {"d1/foo1.txt"}.NOT.file_exist?
|
1612
|
+
ok {"d1/foo2.txt"}.NOT.file_exist?
|
1613
|
+
end
|
1614
|
+
end
|
1615
|
+
end
|
1616
|
+
end
|
1617
|
+
|
1618
|
+
|
1619
|
+
topic 'ln!()' do
|
1620
|
+
spec "[!dkqgq] (ln!) overwrites existing destination file." do
|
1621
|
+
sout, serr = capture_sio do
|
1622
|
+
ln :s, "foo1.txt", "foo9.txt"
|
1623
|
+
ok {"foo9.txt"}.symlink_exist?
|
1624
|
+
#
|
1625
|
+
pr = proc { ln :s, "foo2.txt", "foo9.txt" } # ln, symbolic link
|
1626
|
+
ok {pr}.raise?(ArgumentError, "ln: foo9.txt: File exists (to overwrite it, call `ln!` instead of `ln`).")
|
1627
|
+
ln! :s, "foo1.txt", "foo9.txt" # ln!, symbolic link
|
1628
|
+
ok {"foo9.txt"}.symlink_exist?
|
1629
|
+
ok {File.readlink("foo9.txt")} == "foo1.txt"
|
1630
|
+
#
|
1631
|
+
pr = proc { ln "foo2.txt", "foo9.txt" } # ln, hard link
|
1632
|
+
ok {pr}.raise?(ArgumentError, "ln: foo9.txt: File exists (to overwrite it, call `ln!` instead of `ln`).")
|
1633
|
+
ln! "foo2.txt", "foo9.txt" # ln!, hard link
|
1634
|
+
ok {"foo9.txt"}.file_exist?
|
1635
|
+
ok {"foo9.txt"}.NOT.symlink_exist?
|
1636
|
+
end
|
1637
|
+
end
|
1638
|
+
spec "[!c3vwn] (ln!) error when target file is a directory." do
|
1639
|
+
sout, serr = capture_sio do
|
1640
|
+
dummy_dir("d1/foo1.txt")
|
1641
|
+
pr = proc { ln! "foo1.txt", to: "d1" } # hard link
|
1642
|
+
ok {pr}.raise?(ArgumentError, "ln!: d1/foo1.txt: directory already exists.")
|
1643
|
+
#
|
1644
|
+
pr = proc { ln! :s, "foo1.txt", to: "d1" } # symbolic link
|
1645
|
+
ok {pr}.raise?(ArgumentError, "ln!: d1/foo1.txt: directory already exists.")
|
1646
|
+
end
|
1647
|
+
end
|
1648
|
+
spec "[!bfcki] (ln!) overwrites existing symbolic links." do
|
1649
|
+
sout, serr = capture_sio do
|
1650
|
+
ln :s, "d1/bar.txt", "d1/foo1.txt"
|
1651
|
+
ln :s, "d1/bar.txt", "d1/foo2.txt"
|
1652
|
+
ok {"d1/foo1.txt"}.symlink_exist?
|
1653
|
+
ok {"d1/foo2.txt"}.symlink_exist?
|
1654
|
+
#
|
1655
|
+
pr = proc { ln "foo1.txt", to: "d1" }
|
1656
|
+
ok {pr}.raise?(ArgumentError, "ln: d1/foo1.txt: symbolic link already exists (to overwrite it, call `ln!` instead of `ln`).")
|
1657
|
+
ln! "foo1.txt", to: "d1" # hard link
|
1658
|
+
ok {"d1/foo1.txt"}.file_exist?
|
1659
|
+
ok {"d1/foo1.txt"}.NOT.symlink_exist?
|
1660
|
+
#
|
1661
|
+
pr = proc { ln :s, "foo2.txt", to: "d1" }
|
1662
|
+
ok {pr}.raise?(ArgumentError, "ln: d1/foo2.txt: symbolic link already exists (to overwrite it, call `ln!` instead of `ln`).")
|
1663
|
+
ln! :s, "foo2.txt", to: "d1" # symbolic link
|
1664
|
+
ok {"d1/foo2.txt"}.symlink_exist?
|
1665
|
+
ok {"d1/foo2.txt"}.NOT.file_exist?
|
1666
|
+
end
|
1667
|
+
end
|
1668
|
+
spec "[!ipy2c] (ln!) overwrites existing files." do
|
1669
|
+
dummy_file "d1/foo1.txt"
|
1670
|
+
dummy_file "d1/foo2.txt"
|
1671
|
+
sout, serr = capture_sio do
|
1672
|
+
## hard link
|
1673
|
+
pr = proc { ln "foo1.txt", to: "d1" }
|
1674
|
+
ok {pr}.raise?(ArgumentError, "ln: d1/foo1.txt: File exists (to overwrite it, call `ln!` instead of `ln`).")
|
1675
|
+
ln! "foo1.txt", to: "d1"
|
1676
|
+
ok {"d1/foo1.txt"}.file_exist?
|
1677
|
+
ok {"d1/foo1.txt"}.NOT.symlink_exist?
|
1678
|
+
## symbolic link
|
1679
|
+
pr = proc { ln :s, "foo2.txt", to: "d1" }
|
1680
|
+
ok {pr}.raise?(ArgumentError, "ln: d1/foo2.txt: File exists (to overwrite it, call `ln!` instead of `ln`).")
|
1681
|
+
ln! :s, "foo2.txt", to: "d1" # symbolic link
|
1682
|
+
ok {"d1/foo2.txt"}.symlink_exist?
|
1683
|
+
ok {"d1/foo2.txt"}.NOT.file_exist?
|
1684
|
+
end
|
1685
|
+
end
|
1686
|
+
end
|
1687
|
+
|
1688
|
+
topic 'atomic_symlink!()' do
|
1689
|
+
spec "[!gzp4a] creates temporal symlink and rename it when symlink already exists." do
|
1690
|
+
File.symlink("foo1.txt", "tmp.link")
|
1691
|
+
sout, serr = capture_sio do
|
1692
|
+
atomic_symlink! "foo2.txt", "tmp.link"
|
1693
|
+
end
|
1694
|
+
ok {File.readlink("tmp.link")} == "foo2.txt"
|
1695
|
+
ok {sout} =~ /\A\$ ln -s foo2\.txt tmp\.link\.\d+ \&\& mv -Tf tmp\.link\.\d+ tmp.link\n\z/
|
1696
|
+
end
|
1697
|
+
spec "[!lhomw] creates temporal symlink and rename it when symlink not exist." do
|
1698
|
+
sout, serr = capture_sio do
|
1699
|
+
atomic_symlink! "d1", "d1.link"
|
1700
|
+
end
|
1701
|
+
ok {File.readlink("d1.link")} == "d1"
|
1702
|
+
ok {sout} =~ /\A\$ ln -s d1 d1\.link\.\d+ \&\& mv -Tf d1\.link\.\d+ d1\.link\n\z/
|
1703
|
+
end
|
1704
|
+
spec "[!h75kp] error when destination is normal file or directory." do
|
1705
|
+
sout, serr = capture_sio do
|
1706
|
+
pr = proc { atomic_symlink! "foo1.txt", "foo2.txt" }
|
1707
|
+
ok {pr}.raise?(ArgumentError, "atomic_symlink!: foo2.txt: not a symbolic link.")
|
1708
|
+
pr = proc { atomic_symlink! "foo1.txt", "d1" }
|
1709
|
+
ok {pr}.raise?(ArgumentError, "atomic_symlink!: d1: not a symbolic link.")
|
1710
|
+
end
|
1711
|
+
end
|
1712
|
+
end
|
1713
|
+
|
1714
|
+
|
1715
|
+
topic 'pwd()' do
|
1716
|
+
spec "[!aelx6] echoback command and arguments." do
|
1717
|
+
here = Dir.pwd()
|
1718
|
+
sout, serr = capture_sio do
|
1719
|
+
pwd()
|
1720
|
+
end
|
1721
|
+
ok {sout} == ("$ pwd\n"\
|
1722
|
+
"#{here}\n")
|
1723
|
+
end
|
1724
|
+
spec "[!kh3l2] prints current directory path."do
|
1725
|
+
here = Dir.pwd()
|
1726
|
+
sout, serr = capture_sio do
|
1727
|
+
pwd()
|
1728
|
+
end
|
1729
|
+
ok {sout} == ("$ pwd\n"\
|
1730
|
+
"#{here}\n")
|
1731
|
+
end
|
1732
|
+
end
|
1733
|
+
|
1734
|
+
|
1735
|
+
topic 'touch()' do
|
1736
|
+
fixture :ts do
|
1737
|
+
ts = Time.new(2000, 1, 1, 0, 0, 0)
|
1738
|
+
File.utime(ts, ts, "foo1.txt")
|
1739
|
+
File.utime(ts, ts, "foo2.txt")
|
1740
|
+
#File.utime(ts, ts, "d1/bar.txt")
|
1741
|
+
ts
|
1742
|
+
end
|
1743
|
+
#
|
1744
|
+
spec "[!ifxob] echobacks command and arguments." do
|
1745
|
+
sout, serr = capture_sio do
|
1746
|
+
touch "foo1.txt", "foo2.txt"
|
1747
|
+
end
|
1748
|
+
ok {sout} == "$ touch foo1.txt foo2.txt\n"
|
1749
|
+
end
|
1750
|
+
spec "[!c7e51] error when reference file not exist." do
|
1751
|
+
sout, serr = capture_sio do
|
1752
|
+
pr = proc { touch :r, "foo9.txt", "foo1.txt" }
|
1753
|
+
ok {pr}.raise?(ArgumentError, "touch: foo9.txt: not exist.")
|
1754
|
+
end
|
1755
|
+
end
|
1756
|
+
spec "[!pggnv] changes both access time and modification time in default." do |ts|
|
1757
|
+
sout, serr = capture_sio do
|
1758
|
+
ok {File.atime("foo1.txt")} == ts
|
1759
|
+
ok {File.mtime("foo1.txt")} == ts
|
1760
|
+
#
|
1761
|
+
now1 = Time.now
|
1762
|
+
touch "foo1.txt"
|
1763
|
+
now2 = Time.now
|
1764
|
+
ok {File.atime("foo1.txt")}.between?(now1, now2)
|
1765
|
+
ok {File.mtime("foo1.txt")}.between?(now1, now2)
|
1766
|
+
end
|
1767
|
+
end
|
1768
|
+
spec "[!o9h74] expands file name pattern." do |ts|
|
1769
|
+
sout, serr = capture_sio do
|
1770
|
+
ok {File.atime("foo1.txt")} == ts
|
1771
|
+
ok {File.mtime("foo1.txt")} == ts
|
1772
|
+
ok {File.atime("foo2.txt")} == ts
|
1773
|
+
ok {File.mtime("foo2.txt")} == ts
|
1774
|
+
#
|
1775
|
+
now1 = Time.now
|
1776
|
+
touch "foo*.txt"
|
1777
|
+
now2 = Time.now
|
1778
|
+
ok {File.atime("foo1.txt")}.between?(now1, now2)
|
1779
|
+
ok {File.mtime("foo1.txt")}.between?(now1, now2)
|
1780
|
+
ok {File.atime("foo2.txt")}.between?(now1, now2)
|
1781
|
+
ok {File.mtime("foo2.txt")}.between?(now1, now2)
|
1782
|
+
end
|
1783
|
+
end
|
1784
|
+
spec "[!9ahsu] changes timestamp of files to current datetime." do |ts|
|
1785
|
+
sout, serr = capture_sio do
|
1786
|
+
ok {File.atime("foo1.txt")} == ts
|
1787
|
+
ok {File.mtime("foo1.txt")} == ts
|
1788
|
+
#
|
1789
|
+
now1 = Time.now
|
1790
|
+
touch "foo1.txt"
|
1791
|
+
now2 = Time.now
|
1792
|
+
ok {File.atime("foo1.txt")}.between?(now1, now2)
|
1793
|
+
ok {File.mtime("foo1.txt")}.between?(now1, now2)
|
1794
|
+
end
|
1795
|
+
end
|
1796
|
+
spec "[!wo080] if reference file specified, use it's timestamp." do |ts|
|
1797
|
+
sout, serr = capture_sio do
|
1798
|
+
ok {File.atime("foo1.txt")} == ts
|
1799
|
+
ok {File.mtime("foo1.txt")} == ts
|
1800
|
+
touch :r, "foo1.txt", "d1/bar.txt"
|
1801
|
+
ok {File.atime("d1/bar.txt")} == ts
|
1802
|
+
ok {File.mtime("d1/bar.txt")} == ts
|
1803
|
+
end
|
1804
|
+
end
|
1805
|
+
spec "[!726rq] creates empty file if file not found and '-c' option not specified." do |ts|
|
1806
|
+
sout, serr = capture_sio do
|
1807
|
+
ok {"foo9.txt"}.not_exist?
|
1808
|
+
touch "foo9.txt"
|
1809
|
+
ok {"foo9.txt"}.file_exist?
|
1810
|
+
end
|
1811
|
+
end
|
1812
|
+
spec "[!cfc40] skips non-existing files if '-c' option specified." do
|
1813
|
+
sout, serr = capture_sio do
|
1814
|
+
ok {"foo9.txt"}.not_exist?
|
1815
|
+
touch :c, "foo9.txt"
|
1816
|
+
ok {"foo9.txt"}.not_exist?
|
1817
|
+
end
|
1818
|
+
end
|
1819
|
+
spec "[!s50bp] changes only access timestamp if '-a' option specified." do |ts|
|
1820
|
+
sout, serr = capture_sio do
|
1821
|
+
ok {File.atime("foo1.txt")} == ts
|
1822
|
+
ok {File.mtime("foo1.txt")} == ts
|
1823
|
+
now1 = Time.now
|
1824
|
+
touch :a, "foo1.txt"
|
1825
|
+
now2 = Time.now
|
1826
|
+
ok {File.atime("foo1.txt")}.between?(now1, now2)
|
1827
|
+
ok {File.mtime("foo1.txt")} == ts
|
1828
|
+
end
|
1829
|
+
end
|
1830
|
+
spec "[!k7zap] changes only modification timestamp if '-m' option specified." do |ts|
|
1831
|
+
sout, serr = capture_sio do
|
1832
|
+
ok {File.atime("foo1.txt")} == ts
|
1833
|
+
ok {File.mtime("foo1.txt")} == ts
|
1834
|
+
now1 = Time.now
|
1835
|
+
touch :m, "foo1.txt"
|
1836
|
+
now2 = Time.now
|
1837
|
+
ok {File.atime("foo1.txt")} == ts
|
1838
|
+
ok {File.mtime("foo1.txt")}.between?(now1, now2)
|
1839
|
+
end
|
1840
|
+
end
|
1841
|
+
spec "[!b5c1n] changes both access and modification timestamps in default." do |ts|
|
1842
|
+
sout, serr = capture_sio do
|
1843
|
+
ok {File.atime("foo1.txt")} == ts
|
1844
|
+
ok {File.mtime("foo1.txt")} == ts
|
1845
|
+
now1 = Time.now
|
1846
|
+
touch "foo1.txt"
|
1847
|
+
now2 = Time.now
|
1848
|
+
ok {File.atime("foo1.txt")} != ts
|
1849
|
+
ok {File.mtime("foo1.txt")} != ts
|
1850
|
+
ok {File.atime("foo1.txt")}.between?(now1, now2)
|
1851
|
+
ok {File.mtime("foo1.txt")}.between?(now1, now2)
|
1852
|
+
end
|
1853
|
+
end
|
1854
|
+
end
|
1855
|
+
|
1856
|
+
|
1857
|
+
topic 'chmod()' do
|
1858
|
+
spec "[!pmmvj] echobacks command and arguments." do
|
1859
|
+
sout, serr = capture_sio do
|
1860
|
+
chmod "644", "foo1.txt", "foo2.txt"
|
1861
|
+
end
|
1862
|
+
ok {sout} == "$ chmod 644 foo1.txt foo2.txt\n"
|
1863
|
+
end
|
1864
|
+
spec "[!94hl9] error when mode not specified." do
|
1865
|
+
sout, serr = capture_sio do
|
1866
|
+
pr = proc { chmod() }
|
1867
|
+
ok {pr}.raise?(ArgumentError, "chmod: argument required.")
|
1868
|
+
end
|
1869
|
+
end
|
1870
|
+
spec "[!c8zhu] mode can be integer or octal string." do
|
1871
|
+
sout, serr = capture_sio do
|
1872
|
+
mode_i, mask = __chmod("chmod", [0644, "foo1.txt"], true)
|
1873
|
+
ok {mode_i} == 0644
|
1874
|
+
ok {mask} == nil
|
1875
|
+
mode_i, mask = __chmod("chmod", ["644", "foo1.txt"], true)
|
1876
|
+
ok {mode_i} == 0644
|
1877
|
+
ok {mask} == nil
|
1878
|
+
end
|
1879
|
+
end
|
1880
|
+
spec "[!j3nqp] error when integer mode is invalid." do
|
1881
|
+
sout, serr = capture_sio do
|
1882
|
+
pr = proc { chmod 888, "foo1.txt" }
|
1883
|
+
ok {pr}.raise?(ArgumentError, "chmod: 888: Invalid file mode.")
|
1884
|
+
end
|
1885
|
+
end
|
1886
|
+
spec "[!ox3le] converts 'u+r' style mode into mask." do
|
1887
|
+
sout, serr = capture_sio do
|
1888
|
+
[
|
1889
|
+
["u+r", 0400], ["u+w", 0200], ["u+x", 0100], ["u+s", 04000], ["u+t", 00000],
|
1890
|
+
["g+r", 0040], ["g+w", 0020], ["g+x", 0010], ["g+s", 02000], ["g+t", 00000],
|
1891
|
+
["o+r", 0004], ["o+w", 0002], ["o+x", 0001], ["o+s", 00000], ["o+t", 00000],
|
1892
|
+
["a+r", 0444], ["a+w", 0222], ["a+x", 0111], ["a+s", 06000], ["a+t", 01000],
|
1893
|
+
].each do |mode, expected|
|
1894
|
+
mode_i, mask = __chmod("chmod", [mode, "foo1.txt"], true)
|
1895
|
+
ok {mode_i} == nil
|
1896
|
+
ok {mask} == expected
|
1897
|
+
end
|
1898
|
+
end
|
1899
|
+
end
|
1900
|
+
spec "[!axqed] error when mode is invalid." do
|
1901
|
+
sout, serr = capture_sio do
|
1902
|
+
pr = proc { chmod "888", "foo1.txt" }
|
1903
|
+
ok {pr}.raise?(ArgumentError, "chmod: 888: Invalid file mode.")
|
1904
|
+
pr = proc { chmod "+r", "foo1.txt" }
|
1905
|
+
ok {pr}.raise?(ArgumentError, "chmod: +r: Invalid file mode.")
|
1906
|
+
end
|
1907
|
+
end
|
1908
|
+
spec "[!ru371] expands file pattern." do
|
1909
|
+
sout, serr = capture_sio do
|
1910
|
+
ok {File.readable?("foo1.txt")} == true
|
1911
|
+
ok {File.readable?("foo2.txt")} == true
|
1912
|
+
chmod "u-r", "foo*.txt"
|
1913
|
+
ok {File.readable?("foo1.txt")} == false
|
1914
|
+
ok {File.readable?("foo2.txt")} == false
|
1915
|
+
end
|
1916
|
+
end
|
1917
|
+
spec "[!ou3ih] error when file not exist." do
|
1918
|
+
sout, serr = capture_sio do
|
1919
|
+
pr = proc { chmod "u+r", "blabla" }
|
1920
|
+
ok {pr}.raise?(ArgumentError, "chmod: blabla: No such file or directory.")
|
1921
|
+
end
|
1922
|
+
end
|
1923
|
+
spec "[!8sd4b] error when file pattern not matched to anything." do
|
1924
|
+
sout, serr = capture_sio do
|
1925
|
+
pr = proc { chmod "u+r", "foobar*.txt" }
|
1926
|
+
ok {pr}.raise?(ArgumentError, "chmod: foobar*.txt: No such file or directory.")
|
1927
|
+
end
|
1928
|
+
end
|
1929
|
+
spec "[!q1psx] changes file mode." do
|
1930
|
+
sout, serr = capture_sio do
|
1931
|
+
mode1 = File.stat("foo1.txt").mode
|
1932
|
+
chmod "432", "foo1.txt"
|
1933
|
+
mode2 = File.stat("foo1.txt").mode
|
1934
|
+
ok {mode2} != mode1
|
1935
|
+
ok {mode2 & 0777} == 0432
|
1936
|
+
#
|
1937
|
+
chmod "u+w", "foo1.txt"
|
1938
|
+
ok {File.stat("foo1.txt").mode & 0777} == 0632
|
1939
|
+
chmod "g-x", "foo1.txt"
|
1940
|
+
ok {File.stat("foo1.txt").mode & 0777} == 0622
|
1941
|
+
chmod "a+x", "foo1.txt"
|
1942
|
+
ok {File.stat("foo1.txt").mode & 0777} == 0733
|
1943
|
+
#
|
1944
|
+
chmod "u+s", "foo1.txt"
|
1945
|
+
ok {File.stat("foo1.txt").mode & 07777} == 04733
|
1946
|
+
chmod "g+s", "foo1.txt"
|
1947
|
+
ok {File.stat("foo1.txt").mode & 07777} == 06733
|
1948
|
+
chmod "a-s", "foo1.txt"
|
1949
|
+
ok {File.stat("foo1.txt").mode & 07777} == 00733
|
1950
|
+
chmod "o+s", "foo1.txt"
|
1951
|
+
ok {File.stat("foo1.txt").mode & 07777} == 00733
|
1952
|
+
#
|
1953
|
+
chmod "u+t", "foo1.txt"
|
1954
|
+
ok {File.stat("foo1.txt").mode & 07777} == 00733
|
1955
|
+
chmod "g+t", "foo1.txt"
|
1956
|
+
ok {File.stat("foo1.txt").mode & 07777} == 00733
|
1957
|
+
chmod "o+t", "foo1.txt"
|
1958
|
+
ok {File.stat("foo1.txt").mode & 07777} == 00733
|
1959
|
+
chmod "a+t", "foo1.txt"
|
1960
|
+
ok {File.stat("foo1.txt").mode & 07777} == 01733
|
1961
|
+
chmod "a-t", "foo1.txt"
|
1962
|
+
ok {File.stat("foo1.txt").mode & 07777} == 00733
|
1963
|
+
end
|
1964
|
+
end
|
1965
|
+
spec "[!4en6n] skips symbolic links." do
|
1966
|
+
sout, serr = capture_sio do
|
1967
|
+
File.symlink("foo1.txt", "foo1.link")
|
1968
|
+
mode = File.stat("foo1.txt").mode
|
1969
|
+
chmod 0765, "foo1.link"
|
1970
|
+
ok {File.stat("foo1.txt").mode} == mode
|
1971
|
+
ok {File.stat("foo1.txt").mode | 0777} != 0765
|
1972
|
+
end
|
1973
|
+
end
|
1974
|
+
spec "[!4e7ve] changes mode recursively if '-R' option specified." do
|
1975
|
+
sout, serr = capture_sio do
|
1976
|
+
chmod :R, 0775, "d1"
|
1977
|
+
ok {File.stat("d1" ).mode & 0777} == 0775
|
1978
|
+
ok {File.stat("d1/bar.txt" ).mode & 0777} == 0775
|
1979
|
+
ok {File.stat("d1/d2/baz.txt").mode & 0777} == 0775
|
1980
|
+
end
|
1981
|
+
end
|
1982
|
+
end
|
1983
|
+
|
1984
|
+
|
1985
|
+
topic 'chown()' do
|
1986
|
+
fixture :usr do
|
1987
|
+
ENV['USER'] # TODO
|
1988
|
+
end
|
1989
|
+
fixture :grp do
|
1990
|
+
"staff" # TODO
|
1991
|
+
end
|
1992
|
+
fixture :uid do |usr|
|
1993
|
+
Etc.getpwnam(usr).uid
|
1994
|
+
end
|
1995
|
+
fixture :gid do |grp|
|
1996
|
+
Etc.getgrnam(grp).gid
|
1997
|
+
end
|
1998
|
+
#
|
1999
|
+
spec "[!5jqqv] echobacks command and arguments." do |usr, grp|
|
2000
|
+
sout, serr = capture_sio do
|
2001
|
+
chown "#{usr}:#{grp}", "foo*.txt"
|
2002
|
+
end
|
2003
|
+
ok {sout} == "$ chown #{usr}:#{grp} foo*.txt\n"
|
2004
|
+
end
|
2005
|
+
spec "[!hkxgu] error when owner not specified." do
|
2006
|
+
sout, serr = capture_sio do
|
2007
|
+
pr = proc { chown() }
|
2008
|
+
ok {pr}.raise?(ArgumentError, "chown: argument required.")
|
2009
|
+
end
|
2010
|
+
end
|
2011
|
+
spec "[!0a35v] accepts integer as user id." do |usr, uid|
|
2012
|
+
sout, serr = capture_sio do
|
2013
|
+
ok {uid}.is_a?(Integer)
|
2014
|
+
chown uid, "foo*.txt"
|
2015
|
+
ok {File.stat("foo1.txt").uid} == uid
|
2016
|
+
end
|
2017
|
+
end
|
2018
|
+
spec "[!b5qud] accepts 'user:group' argument." do |usr, grp, uid, gid|
|
2019
|
+
sout, serr = capture_sio do
|
2020
|
+
chown "#{usr}:#{grp}", "foo*.txt"
|
2021
|
+
ok {File.stat("foo1.txt").uid} == uid
|
2022
|
+
ok {File.stat("foo1.txt").gid} == gid
|
2023
|
+
end
|
2024
|
+
end
|
2025
|
+
spec "[!18gf0] accepts 'user' argument." do |usr, grp, uid|
|
2026
|
+
sout, serr = capture_sio do
|
2027
|
+
chown usr, "foo*.txt"
|
2028
|
+
ok {File.stat("foo1.txt").uid} == uid
|
2029
|
+
#
|
2030
|
+
chown usr+":", "foo*.txt"
|
2031
|
+
ok {File.stat("foo1.txt").uid} == uid
|
2032
|
+
end
|
2033
|
+
end
|
2034
|
+
spec "[!mw5tg] accepts ':group' argument." do |usr, grp, gid|
|
2035
|
+
sout, serr = capture_sio do
|
2036
|
+
chown ":#{grp}", "foo*.txt"
|
2037
|
+
ok {File.stat("foo1.txt").gid} == gid
|
2038
|
+
end
|
2039
|
+
end
|
2040
|
+
spec "[!jyecc] converts user name into user id." do |usr, grp, uid|
|
2041
|
+
sout, serr = capture_sio do
|
2042
|
+
uid, gid = __chown("chown", [usr, "foo*.txt"], true)
|
2043
|
+
ok {uid} == uid
|
2044
|
+
end
|
2045
|
+
end
|
2046
|
+
spec "[!kt7mp] error when invalid user name specified." do |usr, grp|
|
2047
|
+
sout, serr = capture_sio do
|
2048
|
+
pr = proc { chown "honyara", "foo*.txt" }
|
2049
|
+
ok {pr}.raise?(ArgumentError, "chown: honyara: unknown user name.")
|
2050
|
+
end
|
2051
|
+
end
|
2052
|
+
spec "[!f7ye0] converts group name into group id." do |usr, grp, uid, gid|
|
2053
|
+
sout, serr = capture_sio do
|
2054
|
+
uid, gid = __chown("chown", ["#{usr}:#{grp}", "foo*.txt"], true)
|
2055
|
+
ok {uid} == uid
|
2056
|
+
ok {gid} == gid
|
2057
|
+
end
|
2058
|
+
end
|
2059
|
+
spec "[!szlsb] error when invalid group name specified." do
|
2060
|
+
sout, serr = capture_sio do
|
2061
|
+
pr = proc { chown ":honyara", "foo*.txt" }
|
2062
|
+
ok {pr}.raise?(ArgumentError, "chown: honyara: unknown group name.")
|
2063
|
+
end
|
2064
|
+
end
|
2065
|
+
spec "[!138eh] expands file pattern." do |usr, grp, uid|
|
2066
|
+
sout, serr = capture_sio do
|
2067
|
+
chown usr, "foo*.txt"
|
2068
|
+
ok {File.stat("foo1.txt").uid} == uid
|
2069
|
+
ok {File.stat("foo2.txt").uid} == uid
|
2070
|
+
end
|
2071
|
+
end
|
2072
|
+
spec "[!tvpey] error when file not exist." do |usr, grp|
|
2073
|
+
sout, serr = capture_sio do
|
2074
|
+
pr = proc { chown usr, "blabla.txt" }
|
2075
|
+
ok {pr}.raise?(ArgumentError, "chown: blabla.txt: No such file or directory.")
|
2076
|
+
end
|
2077
|
+
end
|
2078
|
+
spec "[!ovkk8] error when file pattern not matched to anything." do |usr, grp|
|
2079
|
+
sout, serr = capture_sio do
|
2080
|
+
pr = proc { chown usr, "blabla*.txt" }
|
2081
|
+
ok {pr}.raise?(ArgumentError, "chown: blabla*.txt: No such file or directory.")
|
2082
|
+
end
|
2083
|
+
end
|
2084
|
+
spec "[!7tf3k] changes file mode." do |usr, grp, uid, gid|
|
2085
|
+
sout, serr = capture_sio do
|
2086
|
+
chown "#{usr}:#{grp}", "foo1.txt"
|
2087
|
+
ok {File.stat("foo1.txt").uid} == uid
|
2088
|
+
ok {File.stat("foo1.txt").gid} == gid
|
2089
|
+
end
|
2090
|
+
end
|
2091
|
+
spec "[!m6mrg] skips symbolic links." do |usr, grp|
|
2092
|
+
sout, serr = capture_sio do
|
2093
|
+
File.symlink "foo1.txt", "foo1.link"
|
2094
|
+
File.unlink "foo1.txt"
|
2095
|
+
chown "#{usr}:#{grp}", "foo1.link" # not raise error
|
2096
|
+
end
|
2097
|
+
end
|
2098
|
+
spec "[!b07ff] changes file mode recursively if '-R' option specified." do |usr, grp, uid|
|
2099
|
+
sout, serr = capture_sio do
|
2100
|
+
chown :R, "#{usr}", "d1"
|
2101
|
+
ok {File.stat("d1/d2/baz.txt").uid} == uid
|
2102
|
+
end
|
2103
|
+
end
|
2104
|
+
end
|
2105
|
+
|
2106
|
+
|
2107
|
+
topic 'store()' do
|
2108
|
+
spec "[!9wr1o] error when `to:` keyword argument not specified." do
|
2109
|
+
sout, serr = capture_sio do
|
2110
|
+
pr = proc { store "foo*.txt", "d1" }
|
2111
|
+
ok {pr}.raise?(ArgumentError, /^missing keyword: :?to$/)
|
2112
|
+
end
|
2113
|
+
end
|
2114
|
+
spec "[!n43u2] echoback command and arguments." do
|
2115
|
+
sout, serr = capture_sio do
|
2116
|
+
store "foo*.txt", to: "d1"
|
2117
|
+
end
|
2118
|
+
ok {sout} == "$ store foo*.txt d1\n"
|
2119
|
+
end
|
2120
|
+
spec "[!588e5] error when destination directory not exist." do
|
2121
|
+
sout, serr = capture_sio do
|
2122
|
+
pr = proc { store "foo*.txt", to: "d9" }
|
2123
|
+
ok {pr}.raise?(ArgumentError, "store: d9: directory not found.")
|
2124
|
+
end
|
2125
|
+
end
|
2126
|
+
spec "[!lm43y] error when destination pattern matched to multiple filenames." do
|
2127
|
+
sout, serr = capture_sio do
|
2128
|
+
pr = proc { store "d1", to: "foo*.txt" }
|
2129
|
+
ok {pr}.raise?(ArgumentError, "store: foo*.txt: unexpectedly matched to multiple filenames (foo1.txt, foo2.txt).")
|
2130
|
+
end
|
2131
|
+
end
|
2132
|
+
spec "[!u5zoy] error when destination is not a directory." do
|
2133
|
+
sout, serr = capture_sio do
|
2134
|
+
pr = proc { store "foo*.txt", to: "d1/bar.txt" }
|
2135
|
+
ok {pr}.raise?(ArgumentError, "store: d1/bar.txt: Not a directory.")
|
2136
|
+
end
|
2137
|
+
end
|
2138
|
+
spec "[!g1duw] error when absolute path specified." do
|
2139
|
+
sout, serr = capture_sio do
|
2140
|
+
pr = proc { store "/tmp", to: "d1" }
|
2141
|
+
ok {pr}.raise?(ArgumentError, "store: /tmp: absolute path not expected (only relative path expected).")
|
2142
|
+
end
|
2143
|
+
end
|
2144
|
+
spec "[!je1i2] error when file not exist but '-f' option not specified." do
|
2145
|
+
sout, serr = capture_sio do
|
2146
|
+
pr = proc { store "blabla*.txt", to: "d1"}
|
2147
|
+
ok {pr}.raise?(ArgumentError, "store: blabla*.txt: file or directory not found (add '-f' option to ignore missing files).")
|
2148
|
+
end
|
2149
|
+
end
|
2150
|
+
spec "[!5619q] (store) error when target file or directory already exists." do
|
2151
|
+
sout, serr = capture_sio do
|
2152
|
+
dummy_file "d1/foo2.txt", "dummy"
|
2153
|
+
pr = proc { store "foo*.txt", to: "d1" }
|
2154
|
+
ok {pr}.raise?(ArgumentError, "store: d1/foo2.txt: destination file or directory already exists.")
|
2155
|
+
end
|
2156
|
+
end
|
2157
|
+
spec "[!4y4zy] copy files with keeping filepath." do
|
2158
|
+
sout, serr = capture_sio do
|
2159
|
+
dummy_dir("d9")
|
2160
|
+
store "foo*.txt", "d1", to: "d9"
|
2161
|
+
ok {"d9/foo1.txt"}.file_exist?
|
2162
|
+
ok {"d9/foo2.txt"}.file_exist?
|
2163
|
+
ok {"d9/d1/bar.txt"}.file_exist?
|
2164
|
+
ok {"d9/d1/d2/baz.txt"}.file_exist?
|
2165
|
+
end
|
2166
|
+
end
|
2167
|
+
spec "[!f0n0y] copy timestamps if '-p' option specified." do
|
2168
|
+
sout, serr = capture_sio do
|
2169
|
+
dummy_dir "d9"
|
2170
|
+
atime1 = File.atime("d1/d2/baz.txt")
|
2171
|
+
mtime1 = File.mtime("d1/d2/baz.txt")
|
2172
|
+
atime2 = (x = atime1 - 600; Time.new(x.year, x.month, x.day, x.hour, x.min, x.sec))
|
2173
|
+
mtime2 = (x = mtime1 - 900; Time.new(x.year, x.month, x.day, x.hour, x.min, x.sec))
|
2174
|
+
File.utime(atime2, mtime2, "d1/d2/baz.txt")
|
2175
|
+
store :p, "d1/**/*.txt", to: "d9"
|
2176
|
+
ok {File.atime("d1/d2/baz.txt")} != atime1
|
2177
|
+
ok {File.mtime("d1/d2/baz.txt")} != mtime1
|
2178
|
+
ok {File.atime("d1/d2/baz.txt")} == atime2 # !!!
|
2179
|
+
ok {File.mtime("d1/d2/baz.txt")} == mtime2 # !!!
|
2180
|
+
end
|
2181
|
+
end
|
2182
|
+
spec "[!w8oq6] creates hard links if '-l' option specified." do
|
2183
|
+
sout, serr = capture_sio do
|
2184
|
+
dummy_dir "d9"
|
2185
|
+
store :l, "foo*.txt", "d1/**/*.txt", to: "d9"
|
2186
|
+
ok {File.identical?("foo1.txt", "d9/foo1.txt")} == true
|
2187
|
+
ok {File.identical?("foo2.txt", "d9/foo2.txt")} == true
|
2188
|
+
ok {File.identical?("d1/bar.txt", "d9/d1/bar.txt")} == true
|
2189
|
+
ok {File.identical?("d1/d2/baz.txt", "d9/d1/d2/baz.txt")} == true
|
2190
|
+
end
|
2191
|
+
end
|
2192
|
+
spec "[!7n869] error when copying supecial files such as character device." do
|
2193
|
+
sout, serr = capture_sio do
|
2194
|
+
dummy_dir "d9"
|
2195
|
+
dir = File.join(Dir.pwd(), "d9")
|
2196
|
+
Dir.chdir "/dev" do
|
2197
|
+
pr = proc { store "./null", to: dir }
|
2198
|
+
ok {pr}.raise?(ArgumentError, "store: ./null: cannot copy characterSpecial file.")
|
2199
|
+
end
|
2200
|
+
end
|
2201
|
+
end
|
2202
|
+
end
|
2203
|
+
|
2204
|
+
topic 'store!()' do
|
2205
|
+
spec "[!cw08t] (store!) overwrites existing files." do
|
2206
|
+
dummy_file "d1/foo2.txt", "dummy"
|
2207
|
+
sout, serr = capture_sio do
|
2208
|
+
store! "foo*.txt", to: "d1"
|
2209
|
+
ok {"d1/foo2.txt"}.file_exist?
|
2210
|
+
ok {File.read("d1/foo2.txt")} != "dummy"
|
2211
|
+
ok {File.read("d1/foo2.txt")} == File.read("foo2.txt")
|
2212
|
+
end
|
2213
|
+
end
|
2214
|
+
end
|
2215
|
+
|
2216
|
+
|
2217
|
+
topic 'zip()' do
|
2218
|
+
spec "[!zzvuk] requires 'zip' gem automatically." do
|
2219
|
+
skip_when defined?(::Zip) != nil, "zip gem already required."
|
2220
|
+
ok {defined?(::Zip)} == nil
|
2221
|
+
sout, serr = capture_sio do
|
2222
|
+
zip "foo.zip", "foo*.txt"
|
2223
|
+
end
|
2224
|
+
ok {defined?(::Zip)} != false
|
2225
|
+
ok {defined?(::Zip)} == 'constant'
|
2226
|
+
end
|
2227
|
+
spec "[!zk1qt] echoback command and arguments." do
|
2228
|
+
sout, serr = capture_sio do
|
2229
|
+
zip "foo.zip", "foo*.txt"
|
2230
|
+
end
|
2231
|
+
ok {sout} == "$ zip foo.zip foo*.txt\n"
|
2232
|
+
end
|
2233
|
+
spec "[!lrnj7] zip filename required." do
|
2234
|
+
sout, serr = capture_sio do
|
2235
|
+
pr = proc { zip :r }
|
2236
|
+
ok {pr}.raise?(ArgumentError, "zip: zip filename required.")
|
2237
|
+
end
|
2238
|
+
end
|
2239
|
+
spec "[!umbal] error when zip file glob pattern matched to mutilple filenames." do
|
2240
|
+
sout, serr = capture_sio do
|
2241
|
+
dummy_file "foo1.zip"
|
2242
|
+
dummy_file "foo2.zip"
|
2243
|
+
pr = proc { zip! "foo*.zip", "foo*.txt" }
|
2244
|
+
ok {pr}.raise?(ArgumentError, "zip: foo*.zip: matched to multiple filenames (foo1.zip, foo2.zip).")
|
2245
|
+
end
|
2246
|
+
end
|
2247
|
+
spec "[!oqzna] (zip) raises error if zip file already exists." do
|
2248
|
+
sout, serr = capture_sio do
|
2249
|
+
dummy_file "foo.zip"
|
2250
|
+
pr = proc { zip "foo.zip", "foo*.txt" }
|
2251
|
+
ok {pr}.raise?(ArgumentError, "zip: foo.zip: already exists (to overwrite it, call `zip!` command instead of `zip` command).")
|
2252
|
+
end
|
2253
|
+
end
|
2254
|
+
spec "[!uu8uz] expands glob pattern." do
|
2255
|
+
sout, serr = capture_sio do
|
2256
|
+
pr = proc { zip "foo.zip", "foo*.txt" }
|
2257
|
+
ok {pr}.NOT.raise?(ArgumentError)
|
2258
|
+
end
|
2259
|
+
end
|
2260
|
+
spec "[!nahxa] error if file not exist." do
|
2261
|
+
sout, serr = capture_sio do
|
2262
|
+
pr = proc { zip "foo.zip", "blabla*.txt" }
|
2263
|
+
ok {pr}.raise?(ArgumentError, "zip: blabla*.txt: file or directory not found.")
|
2264
|
+
end
|
2265
|
+
end
|
2266
|
+
spec "[!qsp7c] cannot specify absolute path." do
|
2267
|
+
sout, serr = capture_sio do
|
2268
|
+
pr = proc { zip "foo.zip", "/tmp" }
|
2269
|
+
ok {pr}.raise?(ArgumentError, "zip: /tmp: not support absolute path.")
|
2270
|
+
end
|
2271
|
+
end
|
2272
|
+
spec "[!p8alf] creates zip file." do
|
2273
|
+
sout, serr = capture_sio do
|
2274
|
+
zip "foo.zip", "foo*.txt"
|
2275
|
+
ok {"foo.zip"}.file_exist?
|
2276
|
+
unzip_cmd = capture2 "which unzip"
|
2277
|
+
if ! unzip_cmd.strip.empty?
|
2278
|
+
output = capture2 "#{unzip_cmd.strip} -l foo.zip"
|
2279
|
+
ok {output} =~ /foo1\.txt/
|
2280
|
+
ok {output} =~ /foo2\.txt/
|
2281
|
+
end
|
2282
|
+
end
|
2283
|
+
end
|
2284
|
+
spec "[!3sxmg] supports complession level (0~9)." do
|
2285
|
+
sout, serr = capture_sio do
|
2286
|
+
dummy_file "foo3.txt", "foobar"*10
|
2287
|
+
zip :'0', "foo0.zip", "foo*.txt"
|
2288
|
+
ok {"foo0.zip"}.file_exist?
|
2289
|
+
zip :'1', "foo1.zip", "foo*.txt"
|
2290
|
+
ok {"foo1.zip"}.file_exist?
|
2291
|
+
zip :'9', "foo9.zip", "foo*.txt"
|
2292
|
+
ok {"foo9.zip"}.file_exist?
|
2293
|
+
#
|
2294
|
+
ok {File.size("foo9.zip")} <= File.size("foo1.zip")
|
2295
|
+
ok {File.size("foo1.zip")} < File.size("foo0.zip")
|
2296
|
+
end
|
2297
|
+
end
|
2298
|
+
spec "[!h7yxl] restores value of `Zip.default_compression`." do
|
2299
|
+
val = Zip.default_compression
|
2300
|
+
sout, serr = capture_sio do
|
2301
|
+
zip :'9', "foo9.zip", "foo*.txt"
|
2302
|
+
end
|
2303
|
+
ok {Zip.default_compression} == val
|
2304
|
+
end
|
2305
|
+
spec "[!bgdg7] adds files recursively into zip file if '-r' option specified." do
|
2306
|
+
sout, serr = capture_sio do
|
2307
|
+
zip :r, "foo.zip", "d1"
|
2308
|
+
unzip_cmd = capture2 "which unzip"
|
2309
|
+
if ! unzip_cmd.strip.empty?
|
2310
|
+
output = capture2 "#{unzip_cmd.strip} -l foo.zip"
|
2311
|
+
ok {output} =~ /d1\/bar\.txt/
|
2312
|
+
ok {output} =~ /d1\/d2\/baz\.txt/
|
2313
|
+
end
|
2314
|
+
end
|
2315
|
+
end
|
2316
|
+
spec "[!jgt96] error when special file specified." do
|
2317
|
+
sout, serr = capture_sio do
|
2318
|
+
here = Dir.pwd
|
2319
|
+
Dir.chdir "/dev" do
|
2320
|
+
pr = proc { zip File.join(here, "foo.zip"), "./null" }
|
2321
|
+
ok {pr}.raise?(ArgumentError, "zip: ./null: characterSpecial file not supported.")
|
2322
|
+
end
|
2323
|
+
end
|
2324
|
+
end
|
2325
|
+
spec "[!fvvn8] returns zip file object." do
|
2326
|
+
sout, serr = capture_sio do
|
2327
|
+
ret = zip "foo.zip", "foo*.txt"
|
2328
|
+
ok {ret}.is_a?(Zip::File)
|
2329
|
+
end
|
2330
|
+
end
|
2331
|
+
end
|
2332
|
+
|
2333
|
+
topic 'zip!()' do
|
2334
|
+
spec "[!khbiq] zip filename can be glob pattern." do
|
2335
|
+
sout, serr = capture_sio do
|
2336
|
+
dummy_file "foo.zip"
|
2337
|
+
pr = proc { zip! "*.zip", "foo*.txt" }
|
2338
|
+
ok {pr}.NOT.raise?(ArgumentError)
|
2339
|
+
end
|
2340
|
+
end
|
2341
|
+
spec "[!e995z] (zip!) removes zip file if exists." do
|
2342
|
+
sout, serr = capture_sio do
|
2343
|
+
dummy_file "foo.zip"
|
2344
|
+
pr = proc { zip! "foo.zip", "foo*.txt" }
|
2345
|
+
ok {pr}.NOT.raise?(ArgumentError)
|
2346
|
+
end
|
2347
|
+
end
|
2348
|
+
end
|
2349
|
+
|
2350
|
+
|
2351
|
+
topic 'unzip()' do
|
2352
|
+
spec "[!eqx48] requires 'zip' gem automatically." do
|
2353
|
+
skip_when defined?(::Zip) != nil, "zip gem already required."
|
2354
|
+
ok {defined?(::Zip)} == nil
|
2355
|
+
sout, serr = capture_sio do
|
2356
|
+
begin
|
2357
|
+
unzip "foo.zip"
|
2358
|
+
rescue
|
2359
|
+
end
|
2360
|
+
end
|
2361
|
+
ok {defined?(::Zip)} == 'constant'
|
2362
|
+
end
|
2363
|
+
spec "[!0tedi] extract zip file." do
|
2364
|
+
sout, serr = capture_sio do
|
2365
|
+
zip "foo.zip", "foo*.txt"
|
2366
|
+
rm "foo*.txt"
|
2367
|
+
ok {"foo1.txt"}.not_exist?
|
2368
|
+
ok {"foo2.txt"}.not_exist?
|
2369
|
+
unzip "foo.zip"
|
2370
|
+
ok {"foo1.txt"}.file_exist?
|
2371
|
+
ok {"foo2.txt"}.file_exist?
|
2372
|
+
end
|
2373
|
+
end
|
2374
|
+
spec "[!ednxk] echoback command and arguments." do
|
2375
|
+
sout, serr = capture_sio do
|
2376
|
+
zip "foo.zip", "foo*.txt"
|
2377
|
+
File.unlink("foo1.txt", "foo2.txt")
|
2378
|
+
unzip "foo.zip"
|
2379
|
+
end
|
2380
|
+
ok {sout} == ("$ zip foo.zip foo*.txt\n"\
|
2381
|
+
"$ unzip foo.zip\n")
|
2382
|
+
end
|
2383
|
+
spec "[!1lul7] error if zip file not specified." do
|
2384
|
+
sout, serr = capture_sio do
|
2385
|
+
pr = proc { unzip() }
|
2386
|
+
ok {pr}.raise?(ArgumentError, "unzip: zip filename required.")
|
2387
|
+
pr = proc { unzip :d }
|
2388
|
+
ok {pr}.raise?(ArgumentError, "unzip: zip filename required.")
|
2389
|
+
end
|
2390
|
+
end
|
2391
|
+
spec "[!0yyg8] target directory should not exist, or be empty." do
|
2392
|
+
sout, serr = capture_sio do
|
2393
|
+
zip "foo.zip", "foo*.txt"
|
2394
|
+
mkdir "d8"
|
2395
|
+
unzip :d, "d8", "foo.zip" # empty dir
|
2396
|
+
unzip :d, "d9", "foo.zip" # non-existing dir
|
2397
|
+
end
|
2398
|
+
end
|
2399
|
+
spec "[!1ls2h] error if target directory not empty." do
|
2400
|
+
sout, serr = capture_sio do
|
2401
|
+
zip "foo.zip", "foo*.txt"
|
2402
|
+
pr = proc { unzip :d, "d1", "foo.zip" }
|
2403
|
+
ok {pr}.raise?(ArgumentError, "unzip: d1: directory not empty.")
|
2404
|
+
end
|
2405
|
+
end
|
2406
|
+
spec "[!lb6r5] error if target directory is not a directory." do
|
2407
|
+
sout, serr = capture_sio do
|
2408
|
+
pr = proc { unzip :d, "foo1.txt", "foo2.txt" }
|
2409
|
+
ok {pr}.raise?(ArgumentError, "unzip: foo1.txt: not a directory.")
|
2410
|
+
end
|
2411
|
+
end
|
2412
|
+
spec "[!dzk7c] creates target directory if not exists." do
|
2413
|
+
sout, serr = capture_sio do
|
2414
|
+
zip "foo.zip", "foo*.txt"
|
2415
|
+
unzip :d, "d8/d9", "*.zip"
|
2416
|
+
ok {"d8/d9/foo1.txt"}.file_exist?
|
2417
|
+
ok {"d8/d9/foo2.txt"}.file_exist?
|
2418
|
+
end
|
2419
|
+
end
|
2420
|
+
spec "[!o1ot5] expands glob pattern." do
|
2421
|
+
sout, serr = capture_sio do
|
2422
|
+
zip "foo.zip", "foo*.txt"; File.unlink("foo1.txt", "foo2.txt")
|
2423
|
+
unzip "*.zip"
|
2424
|
+
ok {"foo1.txt"}.file_exist?
|
2425
|
+
ok {"foo2.txt"}.file_exist?
|
2426
|
+
end
|
2427
|
+
end
|
2428
|
+
spec "[!92bh4] error if glob pattern matched to multiple filenames." do
|
2429
|
+
sout, serr = capture_sio do
|
2430
|
+
pr = proc { unzip "*.txt" }
|
2431
|
+
ok {pr}.raise?(ArgumentError, "unzip: *.txt: matched to multiple filenames (foo1.txt foo2.txt).")
|
2432
|
+
end
|
2433
|
+
end
|
2434
|
+
spec "[!esnke] error if zip file not found." do
|
2435
|
+
sout, serr = capture_sio do
|
2436
|
+
pr = proc { unzip "*.zip" }
|
2437
|
+
ok {pr}.raise?(ArgumentError, "unzip: *.zip: zip file not found.")
|
2438
|
+
end
|
2439
|
+
end
|
2440
|
+
spec "[!ekllx] (unzip) error when file already exists." do
|
2441
|
+
sout, serr = capture_sio do
|
2442
|
+
zip "foo.zip", "foo*.txt"
|
2443
|
+
pr = proc { unzip "foo.zip" }
|
2444
|
+
ok {pr}.raise?(ArgumentError, "unzip: foo1.txt: file already exists (to overwrite it, call `unzip!` command instead of `unzip` command).")
|
2445
|
+
end
|
2446
|
+
end
|
2447
|
+
spec "[!zg60i] error if file has absolute path." do
|
2448
|
+
skip_when true, "cannot create zip file containing absolute path."
|
2449
|
+
end
|
2450
|
+
spec "[!ikq5w] if filenames are specified, extracts files matched to them." do
|
2451
|
+
sout, serr = capture_sio do
|
2452
|
+
zip "foo.zip", "foo*.txt"; File.unlink("foo1.txt", "foo2.txt")
|
2453
|
+
unzip "foo.zip", "*2.txt"
|
2454
|
+
ok {"foo1.txt"}.not_exist?
|
2455
|
+
ok {"foo2.txt"}.file_exist?
|
2456
|
+
end
|
2457
|
+
end
|
2458
|
+
spec "[!dy4r4] if '-d' option specified, extracts files under target directory." do
|
2459
|
+
sout, serr = capture_sio do
|
2460
|
+
zip "foo.zip", "foo*.txt"
|
2461
|
+
unzip :d, "d9", "foo.zip"
|
2462
|
+
ok {"d9/foo1.txt"}.file_exist?
|
2463
|
+
ok {"d9/foo2.txt"}.file_exist?
|
2464
|
+
end
|
2465
|
+
end
|
2466
|
+
spec "[!5u645] if '-d' option not specified, extracts files under current directory." do
|
2467
|
+
sout, serr = capture_sio do
|
2468
|
+
zip "foo.zip", "foo*.txt"; File.unlink("foo1.txt", "foo2.txt")
|
2469
|
+
unzip "foo.zip"
|
2470
|
+
ok {"foo1.txt"}.file_exist?
|
2471
|
+
ok {"foo2.txt"}.file_exist?
|
2472
|
+
end
|
2473
|
+
end
|
2474
|
+
end
|
2475
|
+
|
2476
|
+
topic 'unzip!()' do
|
2477
|
+
spec "[!06nyv] (unzip!) overwrites existing files." do
|
2478
|
+
sout, serr = capture_sio do
|
2479
|
+
zip "foo.zip", "foo*.txt"
|
2480
|
+
File.unlink("foo2.txt")
|
2481
|
+
ok {"foo1.txt"}.file_exist?
|
2482
|
+
ok {"foo2.txt"}.not_exist?
|
2483
|
+
pr = proc { unzip! "foo.zip" }
|
2484
|
+
ok {pr}.NOT.raise?(ArgumentError)
|
2485
|
+
ok {"foo1.txt"}.file_exist?
|
2486
|
+
ok {"foo2.txt"}.file_exist?
|
2487
|
+
end
|
2488
|
+
end
|
2489
|
+
end
|
2490
|
+
|
2491
|
+
|
2492
|
+
topic 'time()' do
|
2493
|
+
spec "[!ddl3a] measures elapsed time of block and reports into stderr." do
|
2494
|
+
sout, serr = capture_sio do
|
2495
|
+
time do
|
2496
|
+
puts "sleep 1..."
|
2497
|
+
sleep 1
|
2498
|
+
end
|
2499
|
+
end
|
2500
|
+
ok {sout} == "sleep 1...\n"
|
2501
|
+
ok {serr} =~ /\A\n 1\.\d\d\ds real 0\.\d\d\ds user 0\.\d\d\ds sys\n\z/
|
2502
|
+
end
|
2503
|
+
spec "[!sjf80] (unzip!) `Zip.on_exists_proc` should be recovered." do
|
2504
|
+
sout, serr = capture_sio do
|
2505
|
+
ok {Zip.on_exists_proc} == false
|
2506
|
+
zip "foo.zip", "foo1.txt", "foo2.txt"
|
2507
|
+
unzip! "foo.zip"
|
2508
|
+
ok {Zip.on_exists_proc} == false
|
2509
|
+
end
|
2510
|
+
end
|
2511
|
+
end
|
2512
|
+
|
2513
|
+
|
2514
|
+
end
|
2515
|
+
|
2516
|
+
|
2517
|
+
end
|