| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
####################################################################### |
|
2
|
|
|
|
|
|
|
# $URL: svn+ssh://equilibrious@equilibrious.net/home/equilibrious/svnrepos/chrisdolan/Test-Virtual-Filesystem/lib/Test/Virtual/Filesystem.pm $ |
|
3
|
|
|
|
|
|
|
# $Date: 2008-07-27 21:28:05 -0500 (Sun, 27 Jul 2008) $ |
|
4
|
|
|
|
|
|
|
# $Author: equilibrious $ |
|
5
|
|
|
|
|
|
|
# $Revision: 785 $ |
|
6
|
|
|
|
|
|
|
######################################################################## |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package Test::Virtual::Filesystem; |
|
9
|
|
|
|
|
|
|
|
|
10
|
3
|
|
|
3
|
|
100052
|
use warnings; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
96
|
|
|
11
|
3
|
|
|
3
|
|
17
|
use strict; |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
100
|
|
|
12
|
3
|
|
|
3
|
|
80
|
use 5.008; |
|
|
3
|
|
|
|
|
16
|
|
|
|
3
|
|
|
|
|
128
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
3
|
|
|
3
|
|
2519
|
use English qw(-no_match_vars); |
|
|
3
|
|
|
|
|
10982
|
|
|
|
3
|
|
|
|
|
16
|
|
|
15
|
3
|
|
|
3
|
|
1361
|
use Carp qw(croak); |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
175
|
|
|
16
|
3
|
|
|
3
|
|
18
|
use File::Spec; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
78
|
|
|
17
|
3
|
|
|
3
|
|
3519
|
use List::MoreUtils qw(any); |
|
|
3
|
|
|
|
|
6484
|
|
|
|
3
|
|
|
|
|
262
|
|
|
18
|
3
|
|
|
3
|
|
4816
|
use Attribute::Handlers; |
|
|
3
|
|
|
|
|
16720
|
|
|
|
3
|
|
|
|
|
20
|
|
|
19
|
3
|
|
|
3
|
|
101
|
use Config; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
138
|
|
|
20
|
3
|
|
|
3
|
|
2796
|
use POSIX qw(:errno_h strerror); |
|
|
3
|
|
|
|
|
25659
|
|
|
|
3
|
|
|
|
|
42
|
|
|
21
|
3
|
|
|
3
|
|
15291
|
use Readonly; |
|
|
3
|
|
|
|
|
15819
|
|
|
|
3
|
|
|
|
|
248
|
|
|
22
|
3
|
|
|
3
|
|
27
|
use Test::More; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
39
|
|
|
23
|
3
|
|
|
3
|
|
1055
|
use base 'Test::Class'; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
5252
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
our $VERSION = '0.13'; |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
Readonly::Scalar my $TIME_LENIENCE => 2; # seconds of tolerance between CPU clock and disk mtime |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Currently this must not nest more than one level deep! |
|
30
|
|
|
|
|
|
|
# (due to implementation of deep copy in new() and the static accessor/mutator constructor) |
|
31
|
|
|
|
|
|
|
Readonly::Hash my %feature_defaults => ( |
|
32
|
|
|
|
|
|
|
xattr => 0, |
|
33
|
|
|
|
|
|
|
time => { |
|
34
|
|
|
|
|
|
|
atime => 0, |
|
35
|
|
|
|
|
|
|
mtime => 1, |
|
36
|
|
|
|
|
|
|
ctime => 1, |
|
37
|
|
|
|
|
|
|
}, |
|
38
|
|
|
|
|
|
|
permissions => 0, |
|
39
|
|
|
|
|
|
|
special => { |
|
40
|
|
|
|
|
|
|
fifo => 0, |
|
41
|
|
|
|
|
|
|
}, |
|
42
|
|
|
|
|
|
|
symlink => 1, |
|
43
|
|
|
|
|
|
|
hardlink => { |
|
44
|
|
|
|
|
|
|
nlink => 1, |
|
45
|
|
|
|
|
|
|
}, |
|
46
|
|
|
|
|
|
|
chown => 0, |
|
47
|
|
|
|
|
|
|
); |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# if true, the feature is disabled no matter what. For example, most versions |
|
50
|
|
|
|
|
|
|
# of Windows at this writing do not support symlinks at all, regardless of |
|
51
|
|
|
|
|
|
|
# whether your virtual filesystem supports them |
|
52
|
|
|
|
|
|
|
Readonly::Hash my %feature_disabled => ( |
|
53
|
|
|
|
|
|
|
$Config{d_symlink} ? () : (symlink => 1), |
|
54
|
|
|
|
|
|
|
$Config{d_chown} ? () : (chown => 1), |
|
55
|
|
|
|
|
|
|
eval {require File::ExtAttr; 1;} ? () : (xattr => 1), |
|
56
|
|
|
|
|
|
|
); |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=pod |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=for stopwords TODO CPAN MSWin32 |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head1 NAME |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
Test::Virtual::Filesystem - Validate a filesystem |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
use Test::Virtual::Filesystem; |
|
69
|
|
|
|
|
|
|
Test::Virtual::Filesystem->new({mountdir => '/path/to/test'})->runtests; |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
or with more customization: |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
use Test::Virtual::Filesystem; |
|
74
|
|
|
|
|
|
|
my $test = Test::Virtual::Filesystem->new({mountdir => '/path/to/test', compatible => '0.03'}); |
|
75
|
|
|
|
|
|
|
$test->enable_test_xattr(1); |
|
76
|
|
|
|
|
|
|
$test->enable_test_chown(1); |
|
77
|
|
|
|
|
|
|
$test->enable_test_atime(1); |
|
78
|
|
|
|
|
|
|
$test->runtests; |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
See the file F in this distribution or the file F in |
|
81
|
|
|
|
|
|
|
the L distribution for thorough examples. |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
WARNING: all of the files in the C will be deleted in the C |
|
84
|
|
|
|
|
|
|
method so BE CAREFUL that you specify the right folder! |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=head1 LICENSE |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
Copyright 2008 Chris Dolan, I |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it |
|
91
|
|
|
|
|
|
|
under the same terms as Perl itself. |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
If you are creating a filesystem, say via L or L, you |
|
96
|
|
|
|
|
|
|
need a fairly mundane set of tests to try out lots of typical filesystem |
|
97
|
|
|
|
|
|
|
operations. This package attempts to accumulate a bunch of those tests into a |
|
98
|
|
|
|
|
|
|
handy suite to make it easier for you to test your filesystem. |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
This suite is based on C, a fantastic library for organizing |
|
101
|
|
|
|
|
|
|
tests into bite-sized bundles. The power of Test::Class lets you select a |
|
102
|
|
|
|
|
|
|
subset of tests to run at author time. For example, when I was working on the |
|
103
|
|
|
|
|
|
|
extended attribute (aka C) tests, I found myself typing this: |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
env TEST_METHOD='xattr_.*' perl -Ilib t/filesys.t |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
which runs just the test methods that begin with C. |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
There are several methods that let you turn on or off a subset of the tests. |
|
110
|
|
|
|
|
|
|
For example, if you do not intend that your filesystem will support symbolic |
|
111
|
|
|
|
|
|
|
links, you can invoke C<$test->enable_test_symlink(0)> in your test program |
|
112
|
|
|
|
|
|
|
just before you call C<$test->runtests>. |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 COMPATIBILITY POLICY |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
Every time I add a new test to this suite, I annotate it with a |
|
117
|
|
|
|
|
|
|
version number. If client code specifies an expected version number |
|
118
|
|
|
|
|
|
|
(say, 1.10) and it's running against a newer version or this module |
|
119
|
|
|
|
|
|
|
(say, 1.20) then any newer test will be marked as a TODO test. That |
|
120
|
|
|
|
|
|
|
way if the test fails, it won't regress published code that used to |
|
121
|
|
|
|
|
|
|
work. |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
This policy will allow us to continue adding new filesystem tests |
|
124
|
|
|
|
|
|
|
without worrying about breaking existing CPAN modules. |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=head1 CAVEATS AND LIMITATIONS |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
This module needs a more complete suite of test cases. In particular, tests |
|
129
|
|
|
|
|
|
|
are needed for the following filesystem features: |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
hardlinks |
|
132
|
|
|
|
|
|
|
nlink |
|
133
|
|
|
|
|
|
|
seek/rewinddir, tell/telldir |
|
134
|
|
|
|
|
|
|
read, sysread, syswrite |
|
135
|
|
|
|
|
|
|
overwrite (with open '+<') |
|
136
|
|
|
|
|
|
|
deep directories |
|
137
|
|
|
|
|
|
|
very full directories |
|
138
|
|
|
|
|
|
|
large files |
|
139
|
|
|
|
|
|
|
filenames with spaces |
|
140
|
|
|
|
|
|
|
non-ASCII filenames (maybe constructor should specify the encoding?) |
|
141
|
|
|
|
|
|
|
permissions |
|
142
|
|
|
|
|
|
|
special file types (fifos, sockets, character and block devices, etc) |
|
143
|
|
|
|
|
|
|
chown |
|
144
|
|
|
|
|
|
|
binmode, non-binmode |
|
145
|
|
|
|
|
|
|
eof |
|
146
|
|
|
|
|
|
|
fileno |
|
147
|
|
|
|
|
|
|
statfs (AKA `df` or `mount`) |
|
148
|
|
|
|
|
|
|
rename corner cases: |
|
149
|
|
|
|
|
|
|
* dest inside src |
|
150
|
|
|
|
|
|
|
* src or dest leaf is '.' or '..' |
|
151
|
|
|
|
|
|
|
* src or dest is FS root |
|
152
|
|
|
|
|
|
|
* dest leaf is symlink |
|
153
|
|
|
|
|
|
|
threading and re-entrancy |
|
154
|
|
|
|
|
|
|
file locking? |
|
155
|
|
|
|
|
|
|
async I/O?? |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Any help writing tests (or adapting tests from existing suites) will |
|
158
|
|
|
|
|
|
|
be appreciated! |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head1 METHODS |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
This module is a subclass of L. All methods from that class are |
|
163
|
|
|
|
|
|
|
available, particularly C. |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=over |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item $pkg->new({mountdir =E $mountdir, ...}) |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Create a new test suite which will operate on files contained within the |
|
170
|
|
|
|
|
|
|
specified mount directory. WARNING: any and all files and folders in that |
|
171
|
|
|
|
|
|
|
mount directory will be deleted! |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
The supported options are: |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=over |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=item C |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
This required property indicates where tests should run. |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=item C |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Specify a Test::Virtual::Filesystem version number that is known to |
|
184
|
|
|
|
|
|
|
work. If the actual Test::Virtual::Filesystem version number is |
|
185
|
|
|
|
|
|
|
greater, then any test cases added after the specified compatible |
|
186
|
|
|
|
|
|
|
version are considered C tests. See L for details |
|
187
|
|
|
|
|
|
|
about C tests. |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=back |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=item $self->init() |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Invoked just before then end of C. This exists solely for |
|
194
|
|
|
|
|
|
|
subclassing convenience. This implementation does nothing. |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=back |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=head1 PROPERTIES |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
The following accessor/mutator methods exist to turn on/off various |
|
201
|
|
|
|
|
|
|
features. They all behave in usual Perl fashion: with no argument, |
|
202
|
|
|
|
|
|
|
they return the current value. With one argument, they set the |
|
203
|
|
|
|
|
|
|
current value and return the newly set value. |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=over |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=item $self->enable_test_all() |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
As a getter, checks whether all of the other tests are enabled. |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
As a setter, turns on/off all the tests. |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=item $self->enable_test_xattr() |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Default false. |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=item $self->enable_test_time() |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Default true. If set false, it also sets C, C and C false. |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=item $self->enable_test_atime() |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
Default false. |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=item $self->enable_test_mtime() |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Default true. |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=item $self->enable_test_ctime() |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Default true. |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=item $self->enable_test_permissions() |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Default false. |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=item $self->enable_test_special() |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
Default true. If set false, it also sets C false. |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=item $self->enable_test_fifo() |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Default false. AKA named pipes. |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=item $self->enable_test_symlink() |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
Default true, except for platforms that do not support symlinks (for example |
|
248
|
|
|
|
|
|
|
MSWin32 and cygwin) as determined by C<$Config::Config{d_symlink}>. |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item $self->enable_test_hardlink() |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
AKA the C function. Default true. If set false, this also sets C false. |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=item $self->enable_test_nlink() |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Count hard links. Default true. |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=item $self->enable_test_chown() |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Default false. |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=back |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head1 TEST CASES |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=over |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=cut |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub new { |
|
271
|
3
|
|
|
3
|
1
|
4375
|
my ($pkg, $opts) = @_; |
|
272
|
3
|
|
|
|
|
38
|
my $self = $pkg->SUPER::new(); |
|
273
|
3
|
|
50
|
|
|
1646
|
$opts ||= {}; |
|
274
|
3
|
|
|
|
|
12
|
for my $key (qw(mountdir compatible)) { |
|
275
|
6
|
|
|
|
|
23
|
$self->{$key} = $opts->{$key}; |
|
276
|
|
|
|
|
|
|
} |
|
277
|
9
|
|
|
|
|
72
|
$self->{fs_opts} = { |
|
278
|
|
|
|
|
|
|
# one-level deep copy |
|
279
|
3
|
100
|
|
|
|
30
|
map {$_ => ref $feature_defaults{$_} ? { %{$feature_defaults{$_}} } : $feature_defaults{$_}} |
|
|
21
|
|
|
|
|
482
|
|
|
280
|
|
|
|
|
|
|
keys %feature_defaults, |
|
281
|
|
|
|
|
|
|
}; |
|
282
|
3
|
|
|
|
|
120
|
$self->init; |
|
283
|
3
|
|
|
|
|
7
|
$self->{ntestdir} = 0; |
|
284
|
3
|
|
|
|
|
26
|
return $self; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
sub init { |
|
288
|
|
|
|
|
|
|
# no-op, subclasses may override |
|
289
|
3
|
|
|
3
|
1
|
8
|
return; |
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
{ |
|
293
|
|
|
|
|
|
|
# Create a read-write accessor for each enabling feature |
|
294
|
3
|
|
|
3
|
|
53184
|
no strict 'refs'; ## no critic(NoStrict) |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
1889
|
|
|
295
|
|
|
|
|
|
|
for my $field (keys %feature_defaults) { |
|
296
|
|
|
|
|
|
|
*{'enable_test_'.$field} = sub { |
|
297
|
0
|
0
|
|
0
|
|
0
|
return $_[0]->{fs_opts}->{$field} if @_ == 1; |
|
298
|
0
|
0
|
|
|
|
0
|
return $_[0]->{fs_opts}->{$field} = $_[1] if @_ == 2; |
|
299
|
0
|
|
|
|
|
0
|
croak 'wrong number of arguments to ' . $field; |
|
300
|
|
|
|
|
|
|
}; |
|
301
|
|
|
|
|
|
|
my $val = $feature_defaults{$field}; |
|
302
|
|
|
|
|
|
|
if (ref $val) { |
|
303
|
|
|
|
|
|
|
for my $subfield (keys %{$val}) { |
|
304
|
|
|
|
|
|
|
*{'enable_test_'.$subfield} = sub { |
|
305
|
0
|
0
|
0
|
0
|
|
0
|
return $_[0]->{fs_opts}->{$field} && $_[0]->{fs_opts}->{$field}->{$subfield} if @_ == 1; |
|
306
|
0
|
0
|
0
|
|
|
0
|
return ($_[0]->{fs_opts}->{$field} ||= {})->{$subfield} = $_[1] if @_ == 2; |
|
307
|
0
|
|
|
|
|
0
|
croak 'wrong number of arguments to ' . $subfield; |
|
308
|
|
|
|
|
|
|
}; |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub enable_test_all { |
|
315
|
0
|
|
|
0
|
1
|
0
|
my ($self, @arg) = @_; |
|
316
|
0
|
|
|
|
|
0
|
return $self->_enable_test_all($self->{fs_opts}, @arg); |
|
317
|
|
|
|
|
|
|
} |
|
318
|
|
|
|
|
|
|
sub _enable_test_all { |
|
319
|
0
|
|
|
0
|
|
0
|
my ($self, $hash, @arg) = @_; |
|
320
|
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
0
|
my $all_set = 1; |
|
322
|
0
|
|
|
|
|
0
|
for my $key (keys %{$hash}) { |
|
|
0
|
|
|
|
|
0
|
|
|
323
|
0
|
0
|
|
|
|
0
|
if (ref $hash->{$key}) { |
|
324
|
0
|
|
0
|
|
|
0
|
$all_set = $self->_enable_test_all($hash->{$key}, @arg) && $all_set; #recurse |
|
325
|
|
|
|
|
|
|
} else { |
|
326
|
0
|
0
|
|
|
|
0
|
if (@arg) { |
|
327
|
0
|
0
|
|
|
|
0
|
$hash->{$key} = $arg[0] ? 1 : 0; |
|
328
|
|
|
|
|
|
|
} |
|
329
|
0
|
|
0
|
|
|
0
|
$all_set &&= $hash->{$key}; |
|
330
|
|
|
|
|
|
|
} |
|
331
|
|
|
|
|
|
|
} |
|
332
|
0
|
|
|
|
|
0
|
return $all_set; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=item setup() |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
Runs before every test to prepare a directory for testing. |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=cut |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub setup : Test(setup) { |
|
342
|
48
|
|
|
48
|
1
|
18688
|
my ($self) = @_; |
|
343
|
48
|
50
|
|
|
|
223
|
if (!defined $self->{mountdir}) { |
|
344
|
0
|
|
|
|
|
0
|
croak 'Programmer error: you did not specify a mountdir'; |
|
345
|
|
|
|
|
|
|
} |
|
346
|
48
|
50
|
|
|
|
1159
|
if (!-d $self->{mountdir}) { |
|
347
|
0
|
|
|
|
|
0
|
croak "Your mountdir '$self->{mountdir}' is not a valid directory"; |
|
348
|
|
|
|
|
|
|
} |
|
349
|
48
|
50
|
|
|
|
719
|
if (!File::Spec->file_name_is_absolute($self->{mountdir})) { |
|
350
|
0
|
|
|
|
|
0
|
croak "Your mountdir '$self->{mountdir}' is not an absolute path"; |
|
351
|
|
|
|
|
|
|
} |
|
352
|
48
|
50
|
|
|
|
484
|
if (File::Spec->splitdir($self->{mountdir}) <= 2) { |
|
353
|
0
|
|
|
|
|
0
|
croak "Your mountdir '$self->{mountdir}' is too close to the root of the filesystem." . |
|
354
|
|
|
|
|
|
|
' I am too scared of deleting important files to use it'; |
|
355
|
|
|
|
|
|
|
} |
|
356
|
48
|
|
|
|
|
651
|
$self->{tempdir} = File::Spec->catdir($self->{mountdir}, 'testdir' . ++$self->{ntestdir}); |
|
357
|
48
|
|
|
|
|
4606
|
mkdir $self->{tempdir}; |
|
358
|
48
|
50
|
|
|
|
1021
|
if (! -d $self->{tempdir}) { |
|
359
|
0
|
|
|
|
|
0
|
die 'Failed to create tempdir'; |
|
360
|
|
|
|
|
|
|
} |
|
361
|
48
|
|
|
|
|
246
|
return; |
|
362
|
3
|
|
|
3
|
|
19
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
19
|
|
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=item teardown() |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
Runs after every test to clean up the test directory so the next test |
|
367
|
|
|
|
|
|
|
will have a clean workspace. |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub teardown : Test(teardown) { |
|
372
|
48
|
|
|
48
|
1
|
17167
|
my ($self) = @_; |
|
373
|
48
|
|
|
|
|
189
|
my $tmpdir = delete $self->{tempdir}; |
|
374
|
48
|
50
|
33
|
|
|
1550
|
if (defined $tmpdir && -e $tmpdir) { |
|
375
|
48
|
|
|
|
|
193
|
$self->_cleandir($tmpdir); |
|
376
|
48
|
50
|
|
|
|
351
|
if ($tmpdir ne $self->{mountdir}) { |
|
377
|
48
|
50
|
|
|
|
5368
|
rmdir $tmpdir or die $OS_ERROR; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
} |
|
380
|
48
|
50
|
33
|
|
|
1467
|
if (defined $tmpdir && -d $tmpdir) { |
|
381
|
0
|
|
|
|
|
0
|
die 'Failed to remove tempdir'; |
|
382
|
|
|
|
|
|
|
} |
|
383
|
48
|
|
|
|
|
279
|
return; |
|
384
|
3
|
|
|
3
|
|
1117
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
12
|
|
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
sub _cleandir { |
|
387
|
66
|
|
|
66
|
|
117
|
my ($self, $dir) = @_; |
|
388
|
66
|
|
|
|
|
520
|
for my $file ($self->_read_dir($dir)) { |
|
389
|
182
|
100
|
|
|
|
502
|
next if q{.} eq $file; |
|
390
|
116
|
100
|
|
|
|
270
|
next if q{..} eq $file; |
|
391
|
50
|
|
|
|
|
6839
|
my $path = File::Spec->catfile($dir, $file); |
|
392
|
50
|
50
|
|
|
|
268
|
die 'Internal error: escaped the temp space!' if length $path <= length $self->{mountdir}; |
|
393
|
50
|
50
|
66
|
|
|
2284
|
die 'nonsense missing file: ' . $path if !-l $path && !-e $path; |
|
394
|
50
|
100
|
|
|
|
1966
|
if (-l $path) { |
|
|
|
100
|
|
|
|
|
|
|
395
|
8
|
50
|
|
|
|
689
|
unlink $path or die $OS_ERROR; |
|
396
|
|
|
|
|
|
|
} elsif (-d $path) { |
|
397
|
18
|
|
|
|
|
66
|
$self->_cleandir($path); |
|
398
|
18
|
50
|
|
|
|
1956
|
rmdir $path or die $OS_ERROR; |
|
399
|
|
|
|
|
|
|
} else { |
|
400
|
24
|
50
|
|
|
|
3922
|
unlink $path or die $OS_ERROR; |
|
401
|
|
|
|
|
|
|
} |
|
402
|
|
|
|
|
|
|
} |
|
403
|
66
|
|
|
|
|
175
|
return; |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=item Introduced($version) |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
A subroutine attribute used to flag the Test::Virtual::Filesystem |
|
409
|
|
|
|
|
|
|
version number when that test was introduced. It's used like this: |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub open_nonexistent_file : Tests(1) : Introduced('0.02') { |
|
412
|
|
|
|
|
|
|
ok(!open(my $f, '<', '/tmp/no_such_file')); |
|
413
|
|
|
|
|
|
|
} |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=cut |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
# http://use.perl.org/~ChrisDolan/journal/34906 |
|
418
|
|
|
|
|
|
|
# http://use.perl.org/~ChrisDolan/journal/34920 |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
sub Introduced : ATTR(CODE) { ## no critic(MixedCase) |
|
421
|
134
|
|
|
134
|
1
|
227721
|
my ($class, $symbol, $code_ref, $attr, $introduced_version) = @_; |
|
422
|
134
|
50
|
|
|
|
407
|
if ($symbol eq 'ANON') { |
|
423
|
0
|
|
|
|
|
0
|
warn 'cannot test anonymous subs - you probably loaded ' . __PACKAGE__ . ' too late.' . |
|
424
|
|
|
|
|
|
|
' (after the CHECK block was run)'; |
|
425
|
|
|
|
|
|
|
} else { |
|
426
|
|
|
|
|
|
|
# Wrap the sub in a version test |
|
427
|
3
|
|
|
3
|
|
1409
|
no warnings 'redefine'; ## no critic(TestingAndDebugging::ProhibitNoWarnings) |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
153
|
|
|
428
|
134
|
|
|
|
|
496
|
*{$symbol} = sub { |
|
429
|
3
|
|
|
3
|
|
15
|
no strict 'refs'; ## no critic(TestingAndDebugging::ProhibitNoStrict) |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
271
|
|
|
430
|
43
|
|
|
43
|
|
10340
|
local ${$class.'::TODO'} = $_[0]->_compatible($introduced_version); ## no critic(Local) |
|
|
43
|
|
|
|
|
406
|
|
|
431
|
43
|
|
|
|
|
166
|
$code_ref->(@_); |
|
432
|
134
|
|
|
|
|
468
|
}; |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
#my $name = *{$symbol}{NAME}; |
|
435
|
|
|
|
|
|
|
#print STDERR "record $class\::$name as $introduced_version\n"; |
|
436
|
|
|
|
|
|
|
} |
|
437
|
134
|
|
|
|
|
412
|
return; |
|
438
|
3
|
|
|
3
|
|
15
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
13
|
|
|
439
|
|
|
|
|
|
|
sub _compatible { |
|
440
|
43
|
|
|
43
|
|
81
|
my ($self, $introduced_version) = @_; |
|
441
|
43
|
100
|
|
|
|
186
|
return if !$self->{compatible}; |
|
442
|
2
|
50
|
|
|
|
9
|
return if $introduced_version le $self->{compatible}; |
|
443
|
2
|
|
|
|
|
7
|
return 'compatibility mode ' . $self->{compatible}; |
|
444
|
|
|
|
|
|
|
} |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=item Features($featurelist) |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
This is a subroutine attribute to specify one or more features used in |
|
449
|
|
|
|
|
|
|
the test. The features should be listed as a comma-separated list: |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
sub symlink_create : Tests(1) : Features('symlink') { |
|
452
|
|
|
|
|
|
|
ok(symlink($src, $dest)); |
|
453
|
|
|
|
|
|
|
} |
|
454
|
|
|
|
|
|
|
sub symlink_permissions : Tests(2) : Features('symlink, permissions') { |
|
455
|
|
|
|
|
|
|
ok(symlink($src, $dest)); |
|
456
|
|
|
|
|
|
|
ok(-w $dest); |
|
457
|
|
|
|
|
|
|
} |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
Subfeatures must be separated from their parent features by a C>. For example: |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
sub atime_mtime_set : Tests(1) : Features('time/atime, time/mtime') { |
|
462
|
|
|
|
|
|
|
my $now = time; |
|
463
|
|
|
|
|
|
|
ok(utime($now, $now, $file)); |
|
464
|
|
|
|
|
|
|
} |
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
Look at the source code for C<%feature_defaults> to see the supported features and |
|
467
|
|
|
|
|
|
|
subfeatures. The C methods above describe the all the |
|
468
|
|
|
|
|
|
|
features, but in those methods the subfeature names are flattened. |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=cut |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
sub Features : ATTR(CODE) { ## no critic(MixedCase) |
|
473
|
35
|
|
|
35
|
1
|
6909
|
my ($class, $symbol, $code_ref, $attr, $features) = @_; |
|
474
|
35
|
50
|
|
|
|
112
|
if ($symbol eq 'ANON') { |
|
475
|
0
|
|
|
|
|
0
|
warn 'cannot test anonymous subs - you probably loaded ' . $class . ' too late.' . |
|
476
|
|
|
|
|
|
|
' (after the CHECK block was run)'; |
|
477
|
|
|
|
|
|
|
} else { |
|
478
|
35
|
50
|
|
|
|
80
|
my @features = ref $features ? @{$features} : split m/\s*,\s*/xms, $features; |
|
|
35
|
|
|
|
|
174
|
|
|
479
|
|
|
|
|
|
|
# Wrap the sub in a feature test |
|
480
|
3
|
|
|
3
|
|
1990
|
no warnings 'redefine'; ## no critic(TestingAndDebugging::ProhibitNoWarnings) |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
343
|
|
|
481
|
35
|
|
|
|
|
133
|
*{$symbol} = sub { |
|
482
|
13
|
|
|
13
|
|
2203
|
my $blocking_feature = _blocking_feature(__PACKAGE__, $_[0], @features); |
|
483
|
13
|
100
|
|
|
|
128
|
return $blocking_feature if $blocking_feature; |
|
484
|
8
|
|
|
|
|
37
|
return $code_ref->(@_); |
|
485
|
35
|
|
|
|
|
152
|
}; |
|
486
|
|
|
|
|
|
|
} |
|
487
|
35
|
|
|
|
|
108
|
return; |
|
488
|
3
|
|
|
3
|
|
15
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
11
|
|
|
489
|
|
|
|
|
|
|
sub _blocking_feature { |
|
490
|
13
|
|
|
13
|
|
44
|
my ($pkg, $self, @features) = @_; |
|
491
|
|
|
|
|
|
|
|
|
492
|
13
|
|
|
|
|
31
|
for my $feature (@features) { |
|
493
|
13
|
100
|
|
|
|
125
|
return $feature . ' (no OS support)' if $feature_disabled{$feature}; |
|
494
|
11
|
|
|
|
|
108
|
my $opts = $self->{fs_opts}; |
|
495
|
11
|
|
|
|
|
46
|
for my $part (split m{/}xms, $feature) { |
|
496
|
15
|
50
|
|
|
|
45
|
return $feature if !ref $opts; |
|
497
|
15
|
100
|
|
|
|
51
|
return $feature if !$opts->{$part}; |
|
498
|
12
|
|
|
|
|
42
|
$opts = $opts->{$part}; |
|
499
|
|
|
|
|
|
|
} |
|
500
|
|
|
|
|
|
|
} |
|
501
|
8
|
|
|
|
|
22
|
return; |
|
502
|
|
|
|
|
|
|
} |
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=item stat_dir(), introduced in v0.01 |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=cut |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
sub stat_dir : Test(6) : Introduced('0.01') { |
|
509
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
510
|
1
|
|
|
|
|
6
|
my $f = $self->_file(q{/}); |
|
511
|
1
|
|
|
|
|
25
|
ok(-e $f, 'mount dir exists'); |
|
512
|
1
|
|
|
|
|
416
|
ok(-d $f, 'mount dir is a dir'); |
|
513
|
1
|
|
|
|
|
301
|
ok(!-f $f, 'mount dir is not a file'); |
|
514
|
1
|
|
|
|
|
303
|
ok(!-l $f, 'mount dir is not a symlink'); |
|
515
|
1
|
|
|
|
|
423
|
ok(-r $f, 'mount dir is readable'); |
|
516
|
1
|
|
|
|
|
340
|
ok(-x $f, 'mount dir is searchable'); |
|
517
|
1
|
|
|
|
|
307
|
return; |
|
518
|
3
|
|
|
3
|
|
2308
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
15
|
|
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
## This turned out to be very platform-sensitive. |
|
521
|
|
|
|
|
|
|
# |
|
522
|
|
|
|
|
|
|
# =item stat_dir_size(), introduced in v0.02 |
|
523
|
|
|
|
|
|
|
# |
|
524
|
|
|
|
|
|
|
# =cut |
|
525
|
|
|
|
|
|
|
# |
|
526
|
|
|
|
|
|
|
# sub stat_dir_size : Test(1) : Introduced('0.02') { |
|
527
|
|
|
|
|
|
|
# my ($self) = @_; |
|
528
|
|
|
|
|
|
|
# my $f = $self->_file(q{/}); |
|
529
|
|
|
|
|
|
|
# ok(-s $f, 'mount dir has non-zero size'); |
|
530
|
|
|
|
|
|
|
# return; |
|
531
|
|
|
|
|
|
|
# } |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=item read_dir(), introduced in v0.01 |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=cut |
|
536
|
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub read_dir : Test(3) : Introduced('0.01') { |
|
538
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
539
|
1
|
|
|
|
|
6
|
my $f = $self->_file(q{/}); |
|
540
|
1
|
|
|
|
|
6
|
my @files = $self->_read_dir($f); |
|
541
|
1
|
|
|
|
|
9
|
cmp_ok(scalar @files, '>=', 2, 'dir contains at least two entries'); |
|
542
|
1
|
|
|
|
|
614
|
ok((any { $_ eq q{.} } @files), 'dir contains "."'); |
|
|
2
|
|
|
|
|
9
|
|
|
543
|
1
|
|
|
|
|
425
|
ok((any { $_ eq q{..} } @files), 'dir contains ".."'); |
|
|
1
|
|
|
|
|
5
|
|
|
544
|
1
|
|
|
|
|
408
|
return; |
|
545
|
3
|
|
|
3
|
|
1113
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
13
|
|
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=item read_dir_fail(), introduced in v0.01 |
|
548
|
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=cut |
|
550
|
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub read_dir_fail : Test(2) : Introduced('0.01') { |
|
552
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
553
|
1
|
|
|
|
|
5
|
my $f = $self->_file('/no_such'); |
|
554
|
1
|
|
|
|
|
4
|
eval { |
|
555
|
1
|
|
|
|
|
4
|
$self->_read_dir_die($f); |
|
556
|
|
|
|
|
|
|
}; |
|
557
|
1
|
|
|
|
|
8
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'read non-existent dir'); |
|
558
|
1
|
|
|
|
|
528
|
ok(!-e $f, 'did not make dir'); |
|
559
|
1
|
|
|
|
|
513
|
return; |
|
560
|
3
|
|
|
3
|
|
975
|
} |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
12
|
|
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=item read_file_fail(), introduced in v0.01 |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
=cut |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
sub read_file_fail : Test(2) : Introduced('0.01') { |
|
567
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
568
|
1
|
|
|
|
|
16
|
my $f = $self->_file('/read_file_fail'); |
|
569
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
570
|
1
|
|
|
|
|
3
|
eval { |
|
571
|
1
|
|
|
|
|
4
|
$self->_read_file_die($f); |
|
572
|
|
|
|
|
|
|
}; |
|
573
|
1
|
|
|
|
|
7
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'read non-existent file'); |
|
574
|
1
|
|
|
|
|
547
|
ok(!-e $f, 'did not make file'); |
|
575
|
1
|
|
|
|
|
418
|
return; |
|
576
|
3
|
|
|
3
|
|
1026
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
16
|
|
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=item write_empty_file(), introduced in v0.01 |
|
579
|
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
=cut |
|
581
|
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
sub write_empty_file : Test(2) : Introduced('0.01') { |
|
583
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
584
|
1
|
|
|
|
|
16
|
my $f = $self->_file('/create_file'); |
|
585
|
1
|
|
|
|
|
6
|
$self->_write_file($f); |
|
586
|
1
|
|
|
|
|
25
|
ok(-f $f, 'created empty file'); |
|
587
|
1
|
|
|
|
|
377
|
is(-s $f, 0, 'file got right size'); |
|
588
|
1
|
|
|
|
|
298
|
return; |
|
589
|
3
|
|
|
3
|
|
923
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
13
|
|
|
590
|
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=item write_file(), introduced in v0.01 |
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=cut |
|
594
|
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
sub write_file : Test(2) : Introduced('0.01') { |
|
596
|
1
|
|
|
|
|
2
|
my ($self) = @_; |
|
597
|
1
|
|
|
|
|
6
|
my $f = $self->_file('/write_file'); |
|
598
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
599
|
1
|
|
|
|
|
4
|
$self->_write_file($f, $content); |
|
600
|
1
|
|
|
|
|
25
|
ok(-f $f, 'wrote file'); |
|
601
|
1
|
|
|
|
|
421
|
is(-s $f, length $content, 'file got right size'); |
|
602
|
1
|
|
|
|
|
337
|
return; |
|
603
|
3
|
|
|
3
|
|
975
|
} |
|
|
3
|
|
|
|
|
17
|
|
|
|
3
|
|
|
|
|
14
|
|
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=item write_file_subdir_fail(), introduced in v0.01 |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
=cut |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
sub write_file_subdir_fail : Test(2) : Introduced('0.01') { |
|
610
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
611
|
1
|
|
|
|
|
5
|
my $f = $self->_file('/no_such/write_file'); |
|
612
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
613
|
1
|
|
|
|
|
2
|
eval { |
|
614
|
1
|
|
|
|
|
4
|
$self->_write_file($f, $content); |
|
615
|
|
|
|
|
|
|
}; |
|
616
|
1
|
|
|
|
|
7
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'write to non-existent folder'); |
|
617
|
1
|
|
|
|
|
357
|
ok(!-f $f, 'did not make file'); |
|
618
|
1
|
|
|
|
|
337
|
return; |
|
619
|
3
|
|
|
3
|
|
1061
|
} |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
13
|
|
|
620
|
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=item write_append_file(), introduced in v0.01 |
|
622
|
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
=cut |
|
624
|
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
sub write_append_file : Test(2) : Introduced('0.01') { |
|
626
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
627
|
1
|
|
|
|
|
5
|
my $f = $self->_file('/append_file'); |
|
628
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
629
|
1
|
|
|
|
|
5
|
$self->_write_file($f, $content); |
|
630
|
1
|
|
|
|
|
8
|
$self->_append_file($f, $content); |
|
631
|
1
|
|
|
|
|
28
|
ok(-f $f, 'wrote file'); |
|
632
|
1
|
|
|
|
|
439
|
ok(-s $f == 2 * length $content, 'file got right size'); |
|
633
|
1
|
|
|
|
|
325
|
return; |
|
634
|
3
|
|
|
3
|
|
964
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
18
|
|
|
635
|
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
## Perl's '>>' creates the file if it doesn't exist |
|
637
|
|
|
|
|
|
|
# |
|
638
|
|
|
|
|
|
|
#=item write_append_file_fail(), introduced in v0.01 |
|
639
|
|
|
|
|
|
|
# |
|
640
|
|
|
|
|
|
|
#=cut |
|
641
|
|
|
|
|
|
|
# |
|
642
|
|
|
|
|
|
|
# sub write_append_file_fail : Test(2) : Introduced('0.01') { |
|
643
|
|
|
|
|
|
|
# my ($self) = @_; |
|
644
|
|
|
|
|
|
|
# my $f = $self->_file('/append_file_fail'); |
|
645
|
|
|
|
|
|
|
# my $content = 'content'; |
|
646
|
|
|
|
|
|
|
# eval { |
|
647
|
|
|
|
|
|
|
# $self->_append_file($f, $content); |
|
648
|
|
|
|
|
|
|
# }; |
|
649
|
|
|
|
|
|
|
# $self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'append to non-existent file'); |
|
650
|
|
|
|
|
|
|
# ok(!-f $f, 'did not make file'); |
|
651
|
|
|
|
|
|
|
# return; |
|
652
|
|
|
|
|
|
|
# } |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
=item write_read_file(), introduced in v0.01 |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=cut |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
sub write_read_file : Test(1) : Introduced('0.01') { |
|
659
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
660
|
1
|
|
|
|
|
6
|
my $f = $self->_file('/read_file'); |
|
661
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
662
|
1
|
|
|
|
|
8
|
$self->_write_file($f, $content); |
|
663
|
1
|
|
|
|
|
7
|
is($self->_read_file($f), $content, 'read file'); |
|
664
|
1
|
|
|
|
|
435
|
return; |
|
665
|
3
|
|
|
3
|
|
1038
|
} |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
13
|
|
|
666
|
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=item write_read_file_binary(), introduced in v0.08 |
|
668
|
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=cut |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
sub write_read_file_binary : Test(1) : Introduced('0.08') { |
|
672
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
673
|
1
|
|
|
|
|
5
|
my $f = $self->_file('/read_file'); |
|
674
|
1
|
|
|
|
|
5
|
my $content = 'content'; |
|
675
|
1
|
|
|
|
|
7
|
for my $ord (0 .. 0xff, 0 .. 0xff) { ## no critic(MagicNumber) |
|
676
|
512
|
|
|
|
|
762
|
$content .= chr $ord; |
|
677
|
|
|
|
|
|
|
} |
|
678
|
1
|
|
|
|
|
6
|
$self->_write_file($f, $content); |
|
679
|
1
|
|
|
|
|
6
|
is($self->_read_file($f), $content, 'read file'); |
|
680
|
1
|
|
|
|
|
385
|
return; |
|
681
|
3
|
|
|
3
|
|
1149
|
} |
|
|
3
|
|
|
|
|
48
|
|
|
|
3
|
|
|
|
|
14
|
|
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
=item write_unlink_file(), introduced in v0.01 |
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
=cut |
|
686
|
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
sub write_unlink_file : Test(3) : Introduced('0.01') { |
|
688
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
689
|
1
|
|
|
|
|
5
|
my $f = $self->_file('/read_file'); |
|
690
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
691
|
1
|
|
|
|
|
5
|
$self->_write_file($f, $content); |
|
692
|
1
|
|
|
|
|
23
|
ok(-e $f, 'file exists'); |
|
693
|
1
|
|
|
|
|
1077
|
ok(-f $f, 'file is a file'); |
|
694
|
1
|
50
|
|
|
|
529
|
unlink $f or die $OS_ERROR; |
|
695
|
1
|
|
|
|
|
25
|
ok(!-f $f, 'file is deleted'); |
|
696
|
1
|
|
|
|
|
285
|
return; |
|
697
|
3
|
|
|
3
|
|
905
|
} |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
10
|
|
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=item write_mkdir(), introduced in v0.01 |
|
700
|
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=cut |
|
702
|
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
sub write_mkdir : Test(1) : Introduced('0.01') { |
|
704
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
705
|
1
|
|
|
|
|
4
|
my $f = $self->_file('/mk_dir'); |
|
706
|
1
|
50
|
|
|
|
85
|
mkdir $f or die $OS_ERROR; |
|
707
|
1
|
|
|
|
|
22
|
ok(-d $f, 'made dir'); |
|
708
|
1
|
|
|
|
|
326
|
return; |
|
709
|
3
|
|
|
3
|
|
776
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
11
|
|
|
710
|
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
=item write_mkdir_fail(), introduced in v0.01 |
|
712
|
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
=cut |
|
714
|
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
sub write_mkdir_fail : Test(2) : Introduced('0.01') { |
|
716
|
1
|
|
|
|
|
2
|
my ($self) = @_; |
|
717
|
1
|
|
|
|
|
4
|
my $f = $self->_file('/no_such/mk_dir'); |
|
718
|
1
|
|
|
|
|
3
|
eval { |
|
719
|
1
|
50
|
|
|
|
43
|
mkdir $f or die $OS_ERROR; |
|
720
|
|
|
|
|
|
|
}; |
|
721
|
1
|
|
|
|
|
7
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'mkdir at non-existent path'); |
|
722
|
1
|
|
|
|
|
330
|
ok(!-d $f, 'did not make dir'); |
|
723
|
1
|
|
|
|
|
393
|
return; |
|
724
|
3
|
|
|
3
|
|
879
|
} |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
13
|
|
|
725
|
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=item write_rmdir(), introduced in v0.01 |
|
727
|
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
=cut |
|
729
|
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
sub write_rmdir : Test(2) : Introduced('0.01') { |
|
731
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
732
|
1
|
|
|
|
|
5
|
my $f = $self->_file('/rm_dir'); |
|
733
|
1
|
50
|
|
|
|
81
|
mkdir $f or die $OS_ERROR; |
|
734
|
1
|
|
|
|
|
26
|
ok(-d $f, 'made dir'); |
|
735
|
1
|
50
|
|
|
|
434
|
rmdir $f or die $OS_ERROR; |
|
736
|
1
|
|
|
|
|
26
|
ok(!-d $f, 'made dir'); |
|
737
|
1
|
|
|
|
|
374
|
return; |
|
738
|
3
|
|
|
3
|
|
908
|
} |
|
|
3
|
|
|
|
|
22
|
|
|
|
3
|
|
|
|
|
12
|
|
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
=item write_subdir(), introduced in v0.01 |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
=cut |
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
sub write_subdir : Test(3) : Introduced('0.01') { |
|
745
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
746
|
1
|
|
|
|
|
7
|
my $d = $self->_file('/mk_dir'); |
|
747
|
1
|
|
|
|
|
5
|
my $f = $self->_file('/mk_dir/file'); |
|
748
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
749
|
1
|
50
|
|
|
|
87
|
mkdir $d or die $OS_ERROR; |
|
750
|
1
|
|
|
|
|
69
|
ok(-d $d, 'made dir'); |
|
751
|
1
|
|
|
|
|
372
|
$self->_write_file($f, $content); |
|
752
|
1
|
|
|
|
|
35
|
ok(-f $f, 'wrote file in subdir'); |
|
753
|
1
|
|
|
|
|
412
|
is($self->_read_file($f), $content, 'right content'); |
|
754
|
1
|
|
|
|
|
428
|
return; |
|
755
|
3
|
|
|
3
|
|
1010
|
} |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
11
|
|
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
=item symlink_create(), introduced in v0.02 |
|
758
|
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
=cut |
|
760
|
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
sub symlink_create : Test(10) : Introduced('0.02') : Features('symlink') { |
|
762
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
763
|
1
|
|
|
|
|
4
|
my $target = 'symlink_target'; |
|
764
|
1
|
|
|
|
|
7
|
my $src = $self->_file("/$target"); |
|
765
|
1
|
50
|
|
|
|
85
|
mkdir $src or die $OS_ERROR; |
|
766
|
1
|
|
|
|
|
25
|
ok(-e $src, 'symlink source exists'); |
|
767
|
1
|
|
|
|
|
318
|
my $s = $self->_file('/symlink_create'); |
|
768
|
1
|
50
|
|
|
|
56
|
ok((symlink $target, $s), 'created symlink') or die $OS_ERROR; |
|
769
|
1
|
|
|
|
|
380
|
ok(-e $s, 'symlink exists'); |
|
770
|
1
|
|
|
|
|
285
|
ok(-l $s, 'symlink is a symlink'); |
|
771
|
1
|
|
|
|
|
279
|
ok(-d $s, 'symlink src is a dir'); |
|
772
|
1
|
|
|
|
|
280
|
ok(!-f $s, 'symlink src is not a file'); |
|
773
|
1
|
|
|
|
|
436
|
is(-s $s, -s $src, 'symlink size is size of source'); |
|
774
|
1
|
|
|
|
|
290
|
is(readlink $s, $target, 'read newly created symlink'); |
|
775
|
1
|
50
|
|
|
|
501
|
unlink $s or die $OS_ERROR; |
|
776
|
1
|
|
|
|
|
28
|
ok(!-e $s, 'symlink deleted'); |
|
777
|
1
|
|
|
|
|
301
|
ok(-e $src, 'symlink source not deleted'); |
|
778
|
1
|
|
|
|
|
268
|
return; |
|
779
|
3
|
|
|
3
|
|
1238
|
} |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
12
|
|
|
780
|
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=item symlink_follow(), introduced in v0.04 |
|
782
|
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
=cut |
|
784
|
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
sub symlink_follow : Test(11) : Introduced('0.04') : Features('symlink') { |
|
786
|
1
|
|
|
|
|
2
|
my ($self) = @_; |
|
787
|
1
|
|
|
|
|
4
|
my $target = 'symlink_target'; |
|
788
|
1
|
|
|
|
|
9
|
my $srcdir = $self->_file("/$target"); |
|
789
|
1
|
|
|
|
|
7
|
my $srcfile = $self->_file("/$target/file.txt"); |
|
790
|
1
|
|
|
|
|
6
|
my $s = $self->_file('/symlink_follow'); |
|
791
|
1
|
|
|
|
|
5
|
my $symfile = $s . '/file.txt'; |
|
792
|
1
|
50
|
|
|
|
82
|
mkdir $srcdir or die $OS_ERROR; |
|
793
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
794
|
1
|
|
|
|
|
6
|
$self->_write_file($srcfile, $content); |
|
795
|
1
|
|
|
|
|
26
|
ok(-e $srcfile, 'symlink source exists'); |
|
796
|
1
|
50
|
|
|
|
4163
|
ok((symlink $target, $s), 'created symlink') or die $OS_ERROR; |
|
797
|
1
|
|
|
|
|
812
|
ok(-e $s, 'symlink exists'); |
|
798
|
1
|
|
|
|
|
1201
|
ok(-l $s, 'symlink is a symlink'); |
|
799
|
1
|
|
|
|
|
1231
|
ok(-d $s, 'symlink src is a dir'); |
|
800
|
1
|
|
|
|
|
675
|
ok(!-f $s, 'symlink src is not a file'); |
|
801
|
1
|
|
|
|
|
324
|
is(-s $symfile, length $content, 'size of file though symlink size is size of content'); |
|
802
|
1
|
|
|
|
|
937
|
is($self->_read_file($symfile), $content, 'read file through newly created symlink'); |
|
803
|
1
|
50
|
|
|
|
2173
|
unlink $symfile or die $OS_ERROR; |
|
804
|
1
|
|
|
|
|
38
|
ok(-e $s, 'symlink not deleted'); |
|
805
|
1
|
|
|
|
|
777
|
ok(-e $srcdir, 'symlink target dir is not deleted'); |
|
806
|
1
|
|
|
|
|
1044
|
ok(!-e $srcfile, 'file through symlink is deleted'); |
|
807
|
1
|
|
|
|
|
1010
|
return; |
|
808
|
3
|
|
|
3
|
|
1602
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
12
|
|
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
=item symlink_deep(), introduced in v0.06 |
|
811
|
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=cut |
|
813
|
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
sub symlink_deep : Test(17) : Introduced('0.06') : Features('symlink') { |
|
815
|
1
|
|
|
|
|
2
|
my ($self) = @_; |
|
816
|
|
|
|
|
|
|
# follow through a chain of non-looping symlinks |
|
817
|
1
|
|
|
|
|
4
|
my $target = 'symlink_target'; |
|
818
|
1
|
|
|
|
|
7
|
my $srcdir = $self->_file("/$target"); |
|
819
|
1
|
|
|
|
|
6
|
my $srcfile = $self->_file("/$target/file.txt"); |
|
820
|
|
|
|
|
|
|
# 5 is the limit for Linux. Beyond that, we get ELOOP: Too many levels of symbolic links |
|
821
|
|
|
|
|
|
|
# Other platforms seem to tolerate higher numbers... |
|
822
|
1
|
|
|
|
|
5
|
my @s = map {$self->_file("/symlink_$_")} 1 .. 5; ## no critic(ValuesAndExpressions::ProhibitMagicNumbers) |
|
|
5
|
|
|
|
|
17
|
|
|
823
|
|
|
|
|
|
|
|
|
824
|
1
|
50
|
|
|
|
74
|
mkdir $srcdir or die $OS_ERROR; |
|
825
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
826
|
1
|
|
|
|
|
7
|
$self->_write_file($srcfile, $content); |
|
827
|
1
|
|
|
|
|
78
|
ok(-e $srcfile, 'symlink source exists'); |
|
828
|
1
|
|
|
|
|
483
|
ok(-f $srcfile, 'symlink source is a file'); |
|
829
|
|
|
|
|
|
|
|
|
830
|
1
|
50
|
|
|
|
373
|
ok((symlink $target, $s[0]), 'created symlink') or die $OS_ERROR; |
|
831
|
1
|
|
|
|
|
450
|
for my $i (1..$#s) { |
|
832
|
4
|
50
|
|
|
|
1295
|
ok((symlink 'symlink_' . $i, $s[$i]), 'created symlink') or die $OS_ERROR; |
|
833
|
|
|
|
|
|
|
} |
|
834
|
1
|
|
|
|
|
6361
|
my $symfile = $self->_file('/symlink_'.@s.'/file.txt'); |
|
835
|
1
|
|
|
|
|
105
|
ok(-e $symfile, 'file exists'); # or die 'no symlinked file, cannot continue'; |
|
836
|
1
|
|
|
|
|
1626
|
ok(!-l $symfile, 'file is not a symlink'); |
|
837
|
1
|
|
|
|
|
591
|
ok(-f $symfile, 'file is a file'); |
|
838
|
1
|
|
|
|
|
723
|
ok(!-d $symfile, 'file is not a dir'); |
|
839
|
1
|
|
|
|
|
1026
|
is(-s $symfile, length $content, 'size of file though symlink size is size of content'); |
|
840
|
1
|
|
|
|
|
1071
|
is($self->_read_file($symfile), $content, 'read file through newly created symlink'); |
|
841
|
1
|
50
|
|
|
|
1163
|
unlink $symfile or die $OS_ERROR; |
|
842
|
1
|
|
|
|
|
35
|
ok(-e $s[0], 'symlink not deleted'); |
|
843
|
1
|
|
|
|
|
1405
|
ok(-e $s[-1], 'symlink not deleted'); |
|
844
|
1
|
|
|
|
|
1286
|
ok(-e $srcdir, 'symlink target dir is not deleted'); |
|
845
|
1
|
|
|
|
|
641
|
ok(!-e $srcfile, 'file through symlink is deleted'); |
|
846
|
1
|
|
|
|
|
715
|
return; |
|
847
|
3
|
|
|
3
|
|
2016
|
} |
|
|
3
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
13
|
|
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=item symlink_loop(), introduced in v0.06 |
|
850
|
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
=cut |
|
852
|
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
sub symlink_loop : Test(2) : Introduced('0.06') : Features('symlink') { |
|
854
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
855
|
1
|
|
|
|
|
4
|
my $target = 'symlink_target'; |
|
856
|
1
|
|
|
|
|
6
|
my $s = $self->_file("/$target"); |
|
857
|
1
|
50
|
|
|
|
59
|
ok((symlink $target, $s), 'created symlink') or die $OS_ERROR; |
|
858
|
1
|
|
|
|
|
2682
|
eval { |
|
859
|
1
|
50
|
|
|
|
644
|
open my $fh, '<', $s or die $OS_ERROR; |
|
860
|
0
|
|
|
|
|
0
|
close $fh; ## no critic(InputOutput::RequireCheckedClose) |
|
861
|
|
|
|
|
|
|
}; |
|
862
|
1
|
|
|
|
|
11
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ELOOP()], 'detected symlink loop'); |
|
863
|
|
|
|
|
|
|
|
|
864
|
1
|
|
|
|
|
428
|
return; |
|
865
|
3
|
|
|
3
|
|
1307
|
} |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
10
|
|
|
866
|
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
=item truncate_file(), introduced in v0.06 |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
=cut |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
sub truncate_file : Test(7) : Introduced('0.06') { |
|
872
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
873
|
1
|
|
|
|
|
7
|
my $f = $self->_file(q{/truncate.txt}); |
|
874
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
875
|
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
## no critic(ValuesAndExpressions::ProhibitMagicNumbers) |
|
877
|
1
|
|
|
|
|
7
|
$self->_write_file($f, $content); |
|
878
|
1
|
|
|
|
|
57
|
is(-s $f, length $content, 'wrote test file'); |
|
879
|
1
|
50
|
|
|
|
783
|
ok((truncate $f, 4), 'truncate to 4 bytes') or die $OS_ERROR; |
|
880
|
1
|
|
|
|
|
556
|
is(-s $f, 4, 'correct size'); |
|
881
|
1
|
50
|
|
|
|
801
|
ok((truncate $f, 0), 'truncate to 0 bytes') or die $OS_ERROR; |
|
882
|
1
|
|
|
|
|
570
|
is(-s $f, 0, 'correct size'); |
|
883
|
1
|
50
|
|
|
|
608
|
ok((truncate $f, 0), 'truncate to 0 bytes') or die $OS_ERROR; |
|
884
|
1
|
|
|
|
|
584
|
is(-s $f, 0, 'correct size'); |
|
885
|
1
|
|
|
|
|
623
|
return; |
|
886
|
3
|
|
|
3
|
|
1315
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
14
|
|
|
887
|
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
=item truncate_no_file(), introduced in v0.06 |
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
=cut |
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
sub truncate_no_file : Test(1) : Introduced('0.06') { |
|
893
|
1
|
|
|
|
|
2
|
my ($self) = @_; |
|
894
|
1
|
|
|
|
|
8
|
my $f = $self->_file(q{/truncate.txt}); |
|
895
|
1
|
|
|
|
|
4
|
eval { |
|
896
|
1
|
50
|
|
|
|
44
|
truncate $f, 0 or die $OS_ERROR; |
|
897
|
|
|
|
|
|
|
}; |
|
898
|
1
|
|
|
|
|
7
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'truncate non-existent file'); |
|
899
|
1
|
|
|
|
|
328
|
return; |
|
900
|
3
|
|
|
3
|
|
912
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
16
|
|
|
901
|
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
=item truncate_file_no_dir(), introduced in v0.06 |
|
903
|
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
=cut |
|
905
|
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
sub truncate_file_no_dir : Test(1) : Introduced('0.06') { |
|
907
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
908
|
1
|
|
|
|
|
5
|
my $pseudo_dir = $self->_file(q{/dir}); |
|
909
|
1
|
|
|
|
|
5
|
my $f = $self->_file(q{/dir/truncate.txt}); |
|
910
|
1
|
|
|
|
|
6
|
$self->_write_file($pseudo_dir, 'foo'); |
|
911
|
1
|
|
|
|
|
2
|
eval { |
|
912
|
1
|
50
|
|
|
|
40
|
truncate $f, 0 or die $OS_ERROR; |
|
913
|
|
|
|
|
|
|
}; |
|
914
|
|
|
|
|
|
|
# man 2 truncate says "[ENOTDIR] A component of the path prefix is not a directory." |
|
915
|
|
|
|
|
|
|
# MSWin32 says ENOENT |
|
916
|
1
|
|
|
|
|
9
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOTDIR(), ENOENT()], 'truncate file in non-existent directory'); |
|
917
|
1
|
|
|
|
|
375
|
return; |
|
918
|
3
|
|
|
3
|
|
1063
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
17
|
|
|
919
|
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
=item truncate_dir(), introduced in v0.06 |
|
921
|
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
=cut |
|
923
|
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
sub truncate_dir : Test(1) : Introduced('0.06') { |
|
925
|
1
|
|
|
|
|
5
|
my ($self) = @_; |
|
926
|
1
|
|
|
|
|
8
|
my $d = $self->_file(q{/truncate_dir}); |
|
927
|
1
|
50
|
|
|
|
102
|
mkdir $d or die $OS_ERROR; |
|
928
|
1
|
|
|
|
|
3
|
eval { |
|
929
|
1
|
50
|
|
|
|
245
|
truncate $d, 0 or die $OS_ERROR; |
|
930
|
|
|
|
|
|
|
}; |
|
931
|
|
|
|
|
|
|
# man 2 truncate says "[EISDIR] The named file is a directory." |
|
932
|
|
|
|
|
|
|
# MSWin32 says EACCES |
|
933
|
1
|
|
|
|
|
37
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [EISDIR(), EACCES()], 'truncate dir'); |
|
934
|
1
|
|
|
|
|
549
|
return; |
|
935
|
3
|
|
|
3
|
|
1014
|
} |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
13
|
|
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=item time_mtime_create(), introduced in v0.06 |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
=cut |
|
940
|
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
sub time_mtime_create : Test(2) : Introduced('0.06') : Features('time/mtime') { |
|
942
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
943
|
1
|
|
|
|
|
5
|
my $f = $self->_file(q{/file.txt}); |
|
944
|
|
|
|
|
|
|
|
|
945
|
1
|
|
|
|
|
4
|
my $before = time; |
|
946
|
1
|
|
|
|
|
4
|
$self->_write_file($f); |
|
947
|
1
|
|
|
|
|
2
|
my $after = time; |
|
948
|
|
|
|
|
|
|
|
|
949
|
1
|
|
|
|
|
23
|
my ($mtime) = (stat $f)[9]; ## no critic(ValuesAndExpressions::ProhibitMagicNumbers) |
|
950
|
1
|
50
|
|
|
|
7
|
cmp_ok($mtime, q{>=}, $before - $TIME_LENIENCE, 'mtime vs. before time') |
|
951
|
|
|
|
|
|
|
or diag 'Is your clock out of synch?'; |
|
952
|
1
|
|
|
|
|
349
|
cmp_ok($mtime, q{<=}, $after + $TIME_LENIENCE, 'mtime vs. after time'); |
|
953
|
1
|
|
|
|
|
1558
|
return; |
|
954
|
3
|
|
|
3
|
|
995
|
} |
|
|
3
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
12
|
|
|
955
|
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
=item time_ctime_create(), introduced in v0.06 |
|
957
|
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
=cut |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
sub time_ctime_create : Test(2) : Introduced('0.06') : Features('time/ctime') { |
|
961
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
962
|
1
|
|
|
|
|
7
|
my $f = $self->_file(q{/file.txt}); |
|
963
|
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
# sleep is needed in case of network filesystem time synch errors |
|
965
|
1
|
|
|
|
|
14
|
my $before = time; |
|
966
|
1
|
|
|
|
|
7
|
$self->_write_file($f); |
|
967
|
1
|
|
|
|
|
3
|
my $after = time; |
|
968
|
|
|
|
|
|
|
|
|
969
|
1
|
|
|
|
|
28
|
my ($ctime) = (stat $f)[10]; ## no critic(ValuesAndExpressions::ProhibitMagicNumbers) |
|
970
|
1
|
50
|
|
|
|
8
|
cmp_ok($ctime, q{>=}, $before - $TIME_LENIENCE, 'ctime vs. before time') |
|
971
|
|
|
|
|
|
|
or diag 'Is your clock out of synch?'; |
|
972
|
1
|
|
|
|
|
388
|
cmp_ok($ctime, q{<=}, $after + $TIME_LENIENCE, 'ctime vs. after time'); |
|
973
|
1
|
|
|
|
|
329
|
return; |
|
974
|
3
|
|
|
3
|
|
1153
|
} |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
14
|
|
|
975
|
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
=item time_mtime_set(), introduced in v0.06 |
|
977
|
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
=cut |
|
979
|
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
sub time_mtime_set : Test(1) : Introduced('0.06') : Features('time/mtime') { |
|
981
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
982
|
1
|
|
|
|
|
7
|
my $f = $self->_file(q{/file.txt}); |
|
983
|
|
|
|
|
|
|
|
|
984
|
1
|
|
|
|
|
5
|
$self->_write_file($f); |
|
985
|
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
## no critic(ValuesAndExpressions::ProhibitMagicNumbers) |
|
987
|
1
|
|
|
|
|
23
|
my ($old_atime, $old_mtime) = (stat $f)[8,9]; |
|
988
|
1
|
50
|
|
|
|
49
|
utime $old_atime, $old_mtime - 100, $f or die $OS_ERROR; |
|
989
|
1
|
|
|
|
|
20
|
my ($new_atime, $new_mtime) = (stat $f)[8,9]; |
|
990
|
1
|
|
|
|
|
7
|
is($new_mtime, $old_mtime - 100, 'changed mtime'); |
|
991
|
1
|
|
|
|
|
1866
|
return; |
|
992
|
3
|
|
|
3
|
|
1041
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
11
|
|
|
993
|
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
=item time_atime_set(), introduced in v0.06 |
|
995
|
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=cut |
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
sub time_atime_set : Test(1) : Introduced('0.06') : Features('time/atime') { |
|
999
|
0
|
|
|
|
|
0
|
my ($self) = @_; |
|
1000
|
0
|
|
|
|
|
0
|
my $f = $self->_file(q{/file.txt}); |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
0
|
|
|
|
|
0
|
$self->_write_file($f); |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
## no critic(ValuesAndExpressions::ProhibitMagicNumbers) |
|
1005
|
0
|
|
|
|
|
0
|
my ($old_atime, $old_mtime) = (stat $f)[8,9]; |
|
1006
|
0
|
0
|
|
|
|
0
|
utime $old_atime - 100, $old_mtime, $f or die $OS_ERROR; |
|
1007
|
0
|
|
|
|
|
0
|
my ($new_atime, $new_mtime) = (stat $f)[8,9]; |
|
1008
|
0
|
|
|
|
|
0
|
is($new_atime, $old_atime - 100, 'changed atime'); |
|
1009
|
0
|
|
|
|
|
0
|
return; |
|
1010
|
3
|
|
|
3
|
|
1119
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
12
|
|
|
1011
|
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
=item xattr_list(), introduced in v0.02 |
|
1013
|
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
=cut |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
sub xattr_list : Test(1) : Introduced('0.02') : Features('xattr') { |
|
1017
|
0
|
|
|
|
|
0
|
my ($self) = @_; |
|
1018
|
0
|
|
|
|
|
0
|
my $f = $self->_file(q{/}); |
|
1019
|
0
|
|
|
|
|
0
|
my @attrs = File::ExtAttr::listfattr($f); |
|
1020
|
0
|
|
0
|
|
|
0
|
ok(@attrs == 0 || defined $attrs[0], 'got xattr list'); |
|
1021
|
0
|
|
|
|
|
0
|
return; |
|
1022
|
3
|
|
|
3
|
|
1043
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
52
|
|
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
=item xattr_set(), introduced in v0.02 |
|
1025
|
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
=cut |
|
1027
|
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
sub xattr_set : Test(9) : Introduced('0.02') : Features('xattr') { |
|
1029
|
0
|
|
|
|
|
0
|
my ($self) = @_; |
|
1030
|
|
|
|
|
|
|
|
|
1031
|
0
|
|
|
|
|
0
|
my $f = $self->_file('/foo'); |
|
1032
|
0
|
|
|
|
|
0
|
$self->_write_file($f); |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
0
|
|
|
|
|
0
|
my $xattr_key = 'org.cpan.cdolan'; |
|
1035
|
0
|
|
|
|
|
0
|
my $xattr_value = 'test'; |
|
1036
|
0
|
|
|
|
|
0
|
my $xattr_replace = 'test2'; |
|
1037
|
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
# just in case, clean up. This fails if the value is '0' but that should never happen! |
|
1039
|
0
|
0
|
|
|
|
0
|
if (File::ExtAttr::getfattr($f, $xattr_key)) { |
|
1040
|
0
|
|
|
|
|
0
|
File::ExtAttr::delfattr($f, $xattr_key); |
|
1041
|
|
|
|
|
|
|
} |
|
1042
|
|
|
|
|
|
|
{ |
|
1043
|
|
|
|
|
|
|
# File::ExtAttr doesn't look at $^W or 'no warnings'. Grr... |
|
1044
|
0
|
|
|
|
|
0
|
local $SIG{__WARN__} = sub {}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1045
|
0
|
|
|
|
|
0
|
ok(!File::ExtAttr::setfattr($f, $xattr_key, $xattr_value, {replace => 1}), 'cannot replace missing xattr'); |
|
1046
|
|
|
|
|
|
|
} |
|
1047
|
0
|
|
|
|
|
0
|
ok(File::ExtAttr::setfattr($f, $xattr_key, $xattr_value, {create => 1}), 'create xattr'); |
|
1048
|
0
|
|
|
|
|
0
|
is(File::ExtAttr::getfattr($f, $xattr_key), $xattr_value, 'get xattr'); |
|
1049
|
0
|
|
|
|
|
0
|
ok((any {$xattr_key eq $_} File::ExtAttr::listfattr($f)), 'list xattr'); |
|
|
0
|
|
|
|
|
0
|
|
|
1050
|
|
|
|
|
|
|
{ |
|
1051
|
0
|
|
|
|
|
0
|
local $SIG{__WARN__} = sub {}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1052
|
0
|
|
|
|
|
0
|
ok(!File::ExtAttr::setfattr($f, $xattr_key, $xattr_value, {create => 1}), 'cannot create existing xattr'); |
|
1053
|
|
|
|
|
|
|
} |
|
1054
|
0
|
|
|
|
|
0
|
ok(File::ExtAttr::setfattr($f, $xattr_key, $xattr_replace, {replace => 1}), 'replace xattr'); |
|
1055
|
0
|
|
|
|
|
0
|
is(File::ExtAttr::getfattr($f, $xattr_key), $xattr_replace, 'get xattr'); |
|
1056
|
0
|
|
|
|
|
0
|
ok(File::ExtAttr::delfattr($f, $xattr_key), 'delete xattr'); |
|
1057
|
|
|
|
|
|
|
# Some implementations return undef, some return q{} |
|
1058
|
0
|
|
|
|
|
0
|
my $get = File::ExtAttr::getfattr($f, $xattr_key); |
|
1059
|
0
|
|
0
|
|
|
0
|
ok(!defined $get || q{} eq $get, 'xattr deleted'); |
|
1060
|
|
|
|
|
|
|
|
|
1061
|
0
|
|
|
|
|
0
|
unlink $f; |
|
1062
|
0
|
|
|
|
|
0
|
return; |
|
1063
|
3
|
|
|
3
|
|
1930
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
18
|
|
|
1064
|
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
=item rename_file(), introduced in v0.08 |
|
1066
|
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
=cut |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
sub rename_file : Test(4) : Introduced('0.08') { |
|
1070
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
1071
|
1
|
|
|
|
|
6
|
my $src = $self->_file('/rename_src'); |
|
1072
|
1
|
|
|
|
|
5
|
my $dest = $self->_file('/rename_dest'); |
|
1073
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
1074
|
1
|
|
|
|
|
5
|
$self->_write_file($src, $content); |
|
1075
|
1
|
|
|
|
|
71
|
ok((rename $src, $dest), 'rename'); |
|
1076
|
1
|
|
|
|
|
2035
|
ok(-e $dest, 'dest exists'); |
|
1077
|
1
|
|
|
|
|
970
|
ok(!-e $src, 'src no longer exists'); |
|
1078
|
1
|
|
|
|
|
299
|
is($self->_read_file($dest), $content, 'read dest'); |
|
1079
|
1
|
|
|
|
|
303
|
return; |
|
1080
|
3
|
|
|
3
|
|
1293
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
13
|
|
|
1081
|
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
=item rename_file_exists(), introduced in v0.08 |
|
1083
|
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
=cut |
|
1085
|
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
sub rename_file_exists : Test(4) : Introduced('0.08') { |
|
1087
|
1
|
|
|
|
|
2
|
my ($self) = @_; |
|
1088
|
1
|
|
|
|
|
7
|
my $src = $self->_file('/rename_src'); |
|
1089
|
1
|
|
|
|
|
6
|
my $dest = $self->_file('/rename_dest'); |
|
1090
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
1091
|
1
|
|
|
|
|
7
|
$self->_write_file($src, $content); |
|
1092
|
1
|
|
|
|
|
3
|
$self->_write_file($dest); |
|
1093
|
1
|
|
|
|
|
81
|
ok((rename $src, $dest), 'rename'); |
|
1094
|
1
|
|
|
|
|
593
|
ok(-e $dest, 'dest exists'); |
|
1095
|
1
|
|
|
|
|
575
|
ok(!-e $src, 'src no longer exists'); |
|
1096
|
1
|
|
|
|
|
550
|
is($self->_read_file($dest), $content, 'read dest'); |
|
1097
|
1
|
|
|
|
|
677
|
return; |
|
1098
|
3
|
|
|
3
|
|
1001
|
} |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
14
|
|
|
1099
|
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
=item rename_file_self(), introduced in v0.08 |
|
1101
|
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
=cut |
|
1103
|
|
|
|
|
|
|
|
|
1104
|
|
|
|
|
|
|
sub rename_file_self : Test(4) : Introduced('0.08') { |
|
1105
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
1106
|
1
|
|
|
|
|
4
|
my $src = $self->_file('/rename_src'); |
|
1107
|
1
|
|
|
|
|
3
|
my $dest = $src; |
|
1108
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
1109
|
1
|
|
|
|
|
6
|
$self->_write_file($src, $content); |
|
1110
|
1
|
|
|
|
|
38
|
ok((rename $src, $dest), 'rename'); |
|
1111
|
1
|
|
|
|
|
645
|
ok(-e $dest, 'dest exists'); |
|
1112
|
1
|
|
|
|
|
339
|
ok(-e $src, 'src still exists'); |
|
1113
|
1
|
|
|
|
|
283
|
is($self->_read_file($dest), $content, 'read dest'); |
|
1114
|
1
|
|
|
|
|
289
|
return; |
|
1115
|
3
|
|
|
3
|
|
965
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
23
|
|
|
1116
|
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
=item rename_file_subdir(), introduced in v0.08 |
|
1118
|
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
=cut |
|
1120
|
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
sub rename_file_subdir : Test(4) : Introduced('0.08') { |
|
1122
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
1123
|
1
|
|
|
|
|
5
|
my $srcdir = $self->_file('/rename_srcdir'); |
|
1124
|
1
|
|
|
|
|
5
|
my $src = $self->_file('/rename_srcdir/rename_src'); |
|
1125
|
1
|
|
|
|
|
4
|
my $destdir = $self->_file('/rename_destdir'); |
|
1126
|
1
|
|
|
|
|
3
|
my $dest = $self->_file('/rename_destdir/rename_dest'); |
|
1127
|
1
|
50
|
|
|
|
75
|
mkdir $srcdir or die $OS_ERROR; |
|
1128
|
1
|
50
|
|
|
|
59
|
mkdir $destdir or die $OS_ERROR; |
|
1129
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
1130
|
1
|
|
|
|
|
5
|
$self->_write_file($src, $content); |
|
1131
|
1
|
|
|
|
|
71
|
ok((rename $src, $dest), 'rename'); |
|
1132
|
1
|
|
|
|
|
366
|
ok(-e $dest, 'dest exists'); |
|
1133
|
1
|
|
|
|
|
276
|
ok(!-e $src, 'src no longer exists'); |
|
1134
|
1
|
|
|
|
|
358
|
is($self->_read_file($dest), $content, 'read dest'); |
|
1135
|
1
|
|
|
|
|
284
|
return; |
|
1136
|
3
|
|
|
3
|
|
1262
|
} |
|
|
3
|
|
|
|
|
13
|
|
|
|
3
|
|
|
|
|
14
|
|
|
1137
|
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
=item rename_file_missing_src(), introduced in v0.08 |
|
1139
|
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
=cut |
|
1141
|
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
sub rename_file_missing_src : Test(1) : Introduced('0.08') { |
|
1143
|
1
|
|
|
|
|
160
|
my ($self) = @_; |
|
1144
|
1
|
|
|
|
|
6
|
my $src = $self->_file('/rename_src'); |
|
1145
|
1
|
|
|
|
|
5
|
my $dest = $self->_file('/rename_dest'); |
|
1146
|
1
|
|
|
|
|
3
|
eval { |
|
1147
|
1
|
50
|
|
|
|
53
|
rename $src, $dest or die $OS_ERROR; |
|
1148
|
|
|
|
|
|
|
}; |
|
1149
|
1
|
|
|
|
|
6
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'src file is missing'); |
|
1150
|
1
|
|
|
|
|
326
|
return; |
|
1151
|
3
|
|
|
3
|
|
1098
|
} |
|
|
3
|
|
|
|
|
12
|
|
|
|
3
|
|
|
|
|
14
|
|
|
1152
|
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
=item rename_file_missing_srcdir(), introduced in v0.08 |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
=cut |
|
1156
|
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
sub rename_file_missing_srcdir : Test(1) : Introduced('0.08') { |
|
1158
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
1159
|
1
|
|
|
|
|
4
|
my $srcdir = $self->_file('/rename_srcdir'); |
|
1160
|
1
|
|
|
|
|
5
|
my $src = $self->_file('/rename_srcdir/rename_src'); |
|
1161
|
1
|
|
|
|
|
5
|
my $dest = $self->_file('/rename_dest'); |
|
1162
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
1163
|
1
|
|
|
|
|
2
|
eval { |
|
1164
|
1
|
50
|
|
|
|
39
|
rename $src, $dest or die $OS_ERROR; |
|
1165
|
|
|
|
|
|
|
}; |
|
1166
|
1
|
|
|
|
|
6
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'src dir is missing'); |
|
1167
|
1
|
|
|
|
|
508
|
return; |
|
1168
|
3
|
|
|
3
|
|
1019
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
20
|
|
|
1169
|
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
=item rename_file_missing_destdir(), introduced in v0.08 |
|
1171
|
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
=cut |
|
1173
|
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
sub rename_file_missing_destdir : Test(1) : Introduced('0.08') { |
|
1175
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
1176
|
1
|
|
|
|
|
6
|
my $src = $self->_file('/rename_src'); |
|
1177
|
1
|
|
|
|
|
6
|
my $destdir = $self->_file('/rename_destdir'); |
|
1178
|
1
|
|
|
|
|
4
|
my $dest = $self->_file('/rename_destdir/rename_dest'); |
|
1179
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
1180
|
1
|
|
|
|
|
7
|
$self->_write_file($src, $content); |
|
1181
|
1
|
|
|
|
|
2
|
eval { |
|
1182
|
1
|
50
|
|
|
|
57
|
rename $src, $dest or die $OS_ERROR; |
|
1183
|
|
|
|
|
|
|
}; |
|
1184
|
1
|
|
|
|
|
9
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOENT()], 'dest dir is missing'); |
|
1185
|
1
|
|
|
|
|
371
|
return; |
|
1186
|
3
|
|
|
3
|
|
1135
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
27
|
|
|
1187
|
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
=item rename_dir(), introduced in v0.08 |
|
1189
|
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
=cut |
|
1191
|
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
sub rename_dir : Test(6) : Introduced('0.08') { |
|
1193
|
1
|
|
|
|
|
2
|
my ($self) = @_; |
|
1194
|
1
|
|
|
|
|
4
|
my $src = $self->_file('/rename_src'); |
|
1195
|
1
|
|
|
|
|
5
|
my $srcfile = $self->_file('/rename_src/file.txt'); |
|
1196
|
1
|
|
|
|
|
5
|
my $dest = $self->_file('/rename_dest'); |
|
1197
|
1
|
|
|
|
|
4
|
my $destfile = $self->_file('/rename_dest/file.txt'); |
|
1198
|
1
|
50
|
|
|
|
90
|
mkdir $src or die $OS_ERROR; |
|
1199
|
1
|
|
|
|
|
2
|
my $content = 'content'; |
|
1200
|
1
|
|
|
|
|
5
|
$self->_write_file($srcfile, $content); |
|
1201
|
1
|
|
|
|
|
75
|
ok((rename $src, $dest), 'rename'); |
|
1202
|
1
|
|
|
|
|
541
|
ok(-e $dest, 'dest exists'); |
|
1203
|
1
|
|
|
|
|
456
|
ok(-e $destfile, 'dest file exists'); |
|
1204
|
1
|
|
|
|
|
320
|
ok(!-e $src, 'src no longer exists'); |
|
1205
|
1
|
|
|
|
|
290
|
is_deeply([sort $self->_read_dir($dest)], [qw(. .. file.txt)], 'read dest'); |
|
1206
|
1
|
|
|
|
|
678
|
is($self->_read_file($destfile), $content, 'read dest'); |
|
1207
|
1
|
|
|
|
|
335
|
return; |
|
1208
|
3
|
|
|
3
|
|
1268
|
} |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
14
|
|
|
1209
|
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
=item rename_dir_exists(), introduced in v0.08 |
|
1211
|
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
=cut |
|
1213
|
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
sub rename_dir_exists : Test(6) : Introduced('0.08') { |
|
1215
|
1
|
|
|
|
|
7
|
my ($self) = @_; |
|
1216
|
1
|
|
|
|
|
5
|
my $src = $self->_file('/rename_src'); |
|
1217
|
1
|
|
|
|
|
4
|
my $srcfile = $self->_file('/rename_src/file.txt'); |
|
1218
|
1
|
|
|
|
|
5
|
my $dest = $self->_file('/rename_dest'); |
|
1219
|
1
|
|
|
|
|
4
|
my $destfile = $self->_file('/rename_dest/file.txt'); |
|
1220
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
1221
|
1
|
50
|
|
|
|
80
|
mkdir $src or die $OS_ERROR; |
|
1222
|
1
|
50
|
|
|
|
57
|
mkdir $dest or die $OS_ERROR; |
|
1223
|
1
|
|
|
|
|
6
|
$self->_write_file($srcfile, $content); |
|
1224
|
1
|
50
|
|
|
|
7
|
if ($OSNAME eq 'MSWin32') { |
|
1225
|
|
|
|
|
|
|
# return the skip message |
|
1226
|
0
|
|
|
|
|
0
|
return 'Cannot overwrite directories via rename on Windows'; |
|
1227
|
|
|
|
|
|
|
} |
|
1228
|
1
|
|
|
|
|
139
|
ok((rename $src, $dest), 'rename'); |
|
1229
|
1
|
|
|
|
|
351
|
ok(-e $dest, 'dest exists'); |
|
1230
|
1
|
|
|
|
|
277
|
ok(-e $destfile, 'dest file exists'); |
|
1231
|
1
|
|
|
|
|
278
|
ok(!-e $src, 'src no longer exists'); |
|
1232
|
1
|
|
|
|
|
256
|
is_deeply([sort $self->_read_dir($dest)], [qw(. .. file.txt)], 'read dest'); |
|
1233
|
1
|
|
|
|
|
556
|
is($self->_read_file($destfile), $content, 'read dest'); |
|
1234
|
1
|
|
|
|
|
334
|
return; |
|
1235
|
3
|
|
|
3
|
|
1311
|
} |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
20
|
|
|
1236
|
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
=item rename_dir_notempty(), introduced in v0.08 |
|
1238
|
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
=cut |
|
1240
|
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
sub rename_dir_notempty : Test(1) : Introduced('0.08') { |
|
1242
|
1
|
|
|
|
|
2
|
my ($self) = @_; |
|
1243
|
1
|
|
|
|
|
6
|
my $src = $self->_file('/rename_src'); |
|
1244
|
1
|
|
|
|
|
6
|
my $dest = $self->_file('/rename_dest'); |
|
1245
|
1
|
|
|
|
|
4
|
my $destfile = $self->_file('/rename_dest/file.txt'); |
|
1246
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
1247
|
1
|
50
|
|
|
|
82
|
mkdir $src or die $OS_ERROR; |
|
1248
|
1
|
50
|
|
|
|
71
|
mkdir $dest or die $OS_ERROR; |
|
1249
|
1
|
|
|
|
|
5
|
$self->_write_file($destfile, $content); |
|
1250
|
1
|
|
|
|
|
3
|
eval { |
|
1251
|
1
|
50
|
|
|
|
70
|
rename $src, $dest or die $OS_ERROR; |
|
1252
|
|
|
|
|
|
|
}; |
|
1253
|
|
|
|
|
|
|
# man 2 rename says "[ENOTEMPTY] To is a directory and is not empty." |
|
1254
|
|
|
|
|
|
|
# MSWin32 says EACCES |
|
1255
|
|
|
|
|
|
|
# Solaris says EEXIST |
|
1256
|
1
|
|
|
|
|
8
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOTEMPTY(), EACCES(), EEXIST()], 'dest dir is not empty'); |
|
1257
|
1
|
|
|
|
|
362
|
return; |
|
1258
|
3
|
|
|
3
|
|
1058
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
14
|
|
|
1259
|
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
=item rename_dir_self(), introduced in v0.08 |
|
1261
|
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
=cut |
|
1263
|
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
sub rename_dir_self : Test(5) : Introduced('0.08') { |
|
1265
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
1266
|
1
|
|
|
|
|
5
|
my $src = $self->_file('/rename_src'); |
|
1267
|
1
|
|
|
|
|
5
|
my $srcfile = $self->_file('/rename_src/file.txt'); |
|
1268
|
1
|
|
|
|
|
4
|
my $dest = $src; |
|
1269
|
1
|
|
|
|
|
2
|
my $destfile = $srcfile; |
|
1270
|
1
|
50
|
|
|
|
71
|
mkdir $src or die $OS_ERROR; |
|
1271
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
1272
|
1
|
|
|
|
|
5
|
$self->_write_file($srcfile, $content); |
|
1273
|
1
|
|
|
|
|
33
|
ok((rename $src, $dest), 'rename'); |
|
1274
|
1
|
|
|
|
|
339
|
ok(-e $dest, 'dest exists'); |
|
1275
|
1
|
|
|
|
|
304
|
ok(-e $destfile, 'dest file exists'); |
|
1276
|
1
|
|
|
|
|
257
|
is_deeply([sort $self->_read_dir($dest)], [qw(. .. file.txt)], 'read dest'); |
|
1277
|
1
|
|
|
|
|
559
|
is($self->_read_file($destfile), $content, 'read dest'); |
|
1278
|
1
|
|
|
|
|
273
|
return; |
|
1279
|
3
|
|
|
3
|
|
1089
|
} |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
11
|
|
|
1280
|
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
=item rename_dir_subdir(), introduced in v0.08 |
|
1282
|
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
=cut |
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
sub rename_dir_subdir : Test(6) : Introduced('0.08') { |
|
1286
|
1
|
|
|
|
|
3
|
my ($self) = @_; |
|
1287
|
1
|
|
|
|
|
5
|
my $srcdir = $self->_file('/rename_srcdir'); |
|
1288
|
1
|
|
|
|
|
5
|
my $src = $self->_file('/rename_srcdir/rename_src'); |
|
1289
|
1
|
|
|
|
|
7
|
my $srcfile = $self->_file('/rename_srcdir/rename_src/file.txt'); |
|
1290
|
1
|
|
|
|
|
5
|
my $destdir = $self->_file('/rename_destdir'); |
|
1291
|
1
|
|
|
|
|
5
|
my $dest = $self->_file('/rename_destdir/rename_dest'); |
|
1292
|
1
|
|
|
|
|
5
|
my $destfile = $self->_file('/rename_destdir/rename_dest/file.txt'); |
|
1293
|
1
|
50
|
|
|
|
76
|
mkdir $srcdir or die $OS_ERROR; |
|
1294
|
1
|
50
|
|
|
|
62
|
mkdir $destdir or die $OS_ERROR; |
|
1295
|
1
|
50
|
|
|
|
65
|
mkdir $src or die $OS_ERROR; |
|
1296
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
1297
|
1
|
|
|
|
|
5
|
$self->_write_file($srcfile, $content); |
|
1298
|
1
|
|
|
|
|
80
|
ok((rename $src, $dest), 'rename'); |
|
1299
|
1
|
|
|
|
|
390
|
ok(-e $dest, 'dest exists'); |
|
1300
|
1
|
|
|
|
|
326
|
ok(-e $destfile, 'dest file exists'); |
|
1301
|
1
|
|
|
|
|
315
|
ok(!-e $src, 'src no longer exists'); |
|
1302
|
1
|
|
|
|
|
273
|
is_deeply([sort $self->_read_dir($dest)], [qw(. .. file.txt)], 'read dest'); |
|
1303
|
1
|
|
|
|
|
540
|
is($self->_read_file($destfile), $content, 'read dest'); |
|
1304
|
1
|
|
|
|
|
263
|
return; |
|
1305
|
3
|
|
|
3
|
|
1485
|
} |
|
|
3
|
|
|
|
|
15
|
|
|
|
3
|
|
|
|
|
13
|
|
|
1306
|
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
=item rename_mismatch_dir(), introduced in v0.08 |
|
1308
|
|
|
|
|
|
|
|
|
1309
|
|
|
|
|
|
|
=cut |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
sub rename_mismatch_dir : Test(1) : Introduced('0.08') { |
|
1312
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
1313
|
1
|
|
|
|
|
5
|
my $src = $self->_file('/rename_src'); |
|
1314
|
1
|
|
|
|
|
7
|
my $dest = $self->_file('/rename_dest'); |
|
1315
|
1
|
|
|
|
|
4
|
my $content = 'content'; |
|
1316
|
1
|
|
|
|
|
5
|
$self->_write_file($src, $content); |
|
1317
|
1
|
50
|
|
|
|
72
|
mkdir $dest or die $OS_ERROR; |
|
1318
|
1
|
|
|
|
|
4
|
eval { |
|
1319
|
1
|
50
|
|
|
|
49
|
rename $src, $dest or die $OS_ERROR; |
|
1320
|
|
|
|
|
|
|
}; |
|
1321
|
|
|
|
|
|
|
# man 2 rename says "[EISDIR] 'to' is a directory, but 'from' is not a directory." |
|
1322
|
|
|
|
|
|
|
# MSWin32 says EACCES |
|
1323
|
1
|
|
|
|
|
9
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [EISDIR(), EACCES()], 'dest is a directory'); |
|
1324
|
1
|
|
|
|
|
341
|
return; |
|
1325
|
3
|
|
|
3
|
|
1096
|
} |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
13
|
|
|
1326
|
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
=item rename_mismatch_file(), introduced in v0.08 |
|
1328
|
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
=cut |
|
1330
|
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
sub rename_mismatch_file : Test(1) : Introduced('0.08') { |
|
1332
|
1
|
|
|
|
|
4
|
my ($self) = @_; |
|
1333
|
1
|
|
|
|
|
5
|
my $src = $self->_file('/rename_srcdir'); |
|
1334
|
1
|
|
|
|
|
6
|
my $dest = $self->_file('/rename_destfile.txt'); |
|
1335
|
1
|
50
|
|
|
|
185
|
mkdir $src or die $OS_ERROR; |
|
1336
|
1
|
|
|
|
|
2
|
my $content = 'content'; |
|
1337
|
1
|
|
|
|
|
7
|
$self->_write_file($dest, $content); |
|
1338
|
1
|
50
|
33
|
|
|
14
|
if ($OSNAME eq 'MSWin32' || $OSNAME eq 'cygwin') { |
|
1339
|
|
|
|
|
|
|
# return the skip message |
|
1340
|
0
|
|
|
|
|
0
|
return 'Windows and Cygwin allow rename(, ) instead of failing with ENOTDIR'; |
|
1341
|
|
|
|
|
|
|
} |
|
1342
|
1
|
|
|
|
|
4
|
eval { |
|
1343
|
1
|
50
|
|
|
|
123
|
rename $src, $dest or die $OS_ERROR; |
|
1344
|
|
|
|
|
|
|
}; |
|
1345
|
1
|
|
|
|
|
8
|
$self->_is_errno($EVAL_ERROR, $OS_ERROR, [ENOTDIR()], 'dest is not a directory'); |
|
1346
|
|
|
|
|
|
|
|
|
1347
|
1
|
|
|
|
|
388
|
return; |
|
1348
|
3
|
|
|
3
|
|
1358
|
} |
|
|
3
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
13
|
|
|
1349
|
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
=item rename_symlink(), introduced in v0.08 |
|
1351
|
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
=cut |
|
1353
|
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
sub rename_symlink : Test(6) : Introduced('0.08') : Features('symlink') { |
|
1355
|
1
|
|
|
|
|
13
|
my ($self) = @_; |
|
1356
|
1
|
|
|
|
|
5
|
my $srcfile = $self->_file('/rename_srcfile.txt'); |
|
1357
|
1
|
|
|
|
|
5
|
my $src = $self->_file('/rename_src'); |
|
1358
|
1
|
|
|
|
|
4
|
my $dest = $self->_file('/rename_dest'); |
|
1359
|
1
|
|
|
|
|
3
|
my $content = 'content'; |
|
1360
|
1
|
|
|
|
|
5
|
$self->_write_file($srcfile, $content); |
|
1361
|
1
|
50
|
|
|
|
62
|
symlink $srcfile, $src or die $OS_ERROR; |
|
1362
|
1
|
|
|
|
|
68
|
ok((rename $src, $dest), 'rename'); |
|
1363
|
1
|
|
|
|
|
518
|
ok(-e $dest, 'dest exists'); |
|
1364
|
1
|
|
|
|
|
315
|
ok(-e $srcfile, 'source target file still exists'); |
|
1365
|
1
|
|
|
|
|
392
|
ok(!-e $src, 'src no longer exists'); |
|
1366
|
1
|
|
|
|
|
337
|
ok(-l $dest, 'dest is a symlink'); |
|
1367
|
1
|
|
|
|
|
257
|
is($self->_read_file($dest), $content, 'read dest'); |
|
1368
|
1
|
|
|
|
|
311
|
return; |
|
1369
|
3
|
|
|
3
|
|
1276
|
} |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
14
|
|
|
1370
|
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
######### helpers ######## |
|
1372
|
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
sub _is_errno { |
|
1375
|
14
|
|
|
14
|
|
68
|
my ($self, $eval_error, $os_errno, $expected_errnos, $msg) = @_; |
|
1376
|
14
|
|
|
|
|
124
|
my $num_errno = 0 + $os_errno; |
|
1377
|
14
|
|
|
|
|
37
|
my $str_errno = "$os_errno"; |
|
1378
|
14
|
50
|
33
|
14
|
|
139
|
return pass($msg) if $eval_error && $num_errno && any {$_ == $num_errno} @{$expected_errnos}; |
|
|
14
|
|
33
|
|
|
115
|
|
|
|
14
|
|
|
|
|
152
|
|
|
1379
|
0
|
|
|
|
|
0
|
my $expected_str = join q{, }, map {strerror($_)} @{$expected_errnos}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1380
|
0
|
0
|
|
|
|
0
|
if (!$eval_error) { |
|
|
0
|
0
|
|
|
|
0
|
|
|
1381
|
0
|
|
|
|
|
0
|
return fail("$msg; didn't throw expected exception"); |
|
1382
|
|
|
|
|
|
|
} elsif (1 == @{$expected_errnos}) { |
|
1383
|
0
|
|
|
|
|
0
|
return is("$num_errno ($str_errno)", "$expected_errnos->[0] ($expected_str)", $msg); |
|
1384
|
|
|
|
|
|
|
} else { |
|
1385
|
0
|
|
|
|
|
0
|
return is("$num_errno ($str_errno)", "[@{$expected_errnos}] ($expected_str)", $msg); |
|
|
0
|
|
|
|
|
0
|
|
|
1386
|
|
|
|
|
|
|
} |
|
1387
|
|
|
|
|
|
|
} |
|
1388
|
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
sub _file { |
|
1390
|
81
|
|
|
81
|
|
265
|
my ($self, $path) = @_; |
|
1391
|
81
|
50
|
|
|
|
480
|
$path =~ s{\A /}{}xms or croak 'test paths must be absolute'; |
|
1392
|
|
|
|
|
|
|
# Change path to proper OS format |
|
1393
|
81
|
|
|
|
|
1099
|
return File::Spec->catfile($self->{tempdir}, split m{/}xms, $path); |
|
1394
|
|
|
|
|
|
|
} |
|
1395
|
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
sub _write_file { |
|
1397
|
29
|
|
|
29
|
|
90
|
my ($self, $f, @content) = @_; |
|
1398
|
29
|
100
|
|
|
|
3535
|
open my $fh, '>', $f or die $OS_ERROR; |
|
1399
|
28
|
|
|
|
|
86
|
binmode $fh; |
|
1400
|
28
|
|
|
|
|
65
|
for my $content (@content) { |
|
1401
|
23
|
50
|
|
|
|
40
|
print {$fh} $content or die $OS_ERROR; |
|
|
23
|
|
|
|
|
422
|
|
|
1402
|
|
|
|
|
|
|
} |
|
1403
|
28
|
50
|
|
|
|
1506
|
close $fh or die $OS_ERROR; |
|
1404
|
28
|
|
|
|
|
423
|
return; |
|
1405
|
|
|
|
|
|
|
} |
|
1406
|
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
sub _append_file { |
|
1408
|
1
|
|
|
1
|
|
18
|
my ($self, $f, @content) = @_; |
|
1409
|
1
|
50
|
|
|
|
54
|
open my $fh, '>>', $f or die $OS_ERROR; |
|
1410
|
1
|
|
|
|
|
3
|
binmode $fh; |
|
1411
|
1
|
|
|
|
|
4
|
for my $content (@content) { |
|
1412
|
1
|
50
|
|
|
|
2
|
print {$fh} $content or die $OS_ERROR; |
|
|
1
|
|
|
|
|
9
|
|
|
1413
|
|
|
|
|
|
|
} |
|
1414
|
1
|
50
|
|
|
|
27
|
close $fh or die $OS_ERROR; |
|
1415
|
1
|
|
|
|
|
6
|
return; |
|
1416
|
|
|
|
|
|
|
} |
|
1417
|
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
sub _read_file { |
|
1419
|
14
|
|
|
14
|
|
39
|
my ($self, $f) = @_; |
|
1420
|
14
|
50
|
|
|
|
866
|
open my $fh, '<', $f or return; |
|
1421
|
14
|
|
|
|
|
42
|
binmode $fh; |
|
1422
|
14
|
|
|
|
|
22
|
my $content = do { local $INPUT_RECORD_SEPARATOR = undef; <$fh> }; |
|
|
14
|
|
|
|
|
73
|
|
|
|
14
|
|
|
|
|
392
|
|
|
1423
|
14
|
50
|
|
|
|
402
|
close $fh or return; |
|
1424
|
14
|
|
|
|
|
126
|
return $content; |
|
1425
|
|
|
|
|
|
|
} |
|
1426
|
|
|
|
|
|
|
|
|
1427
|
|
|
|
|
|
|
sub _read_file_die { |
|
1428
|
1
|
|
|
1
|
|
5
|
my ($self, $f) = @_; |
|
1429
|
1
|
50
|
|
|
|
68
|
open my $fh, '<', $f or die $OS_ERROR; |
|
1430
|
0
|
|
|
|
|
0
|
binmode $fh; |
|
1431
|
0
|
|
|
|
|
0
|
my $content = do { local $INPUT_RECORD_SEPARATOR = undef; <$fh> }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1432
|
0
|
0
|
|
|
|
0
|
close $fh or die $OS_ERROR; |
|
1433
|
0
|
|
|
|
|
0
|
return $content; |
|
1434
|
|
|
|
|
|
|
} |
|
1435
|
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
sub _read_dir { |
|
1437
|
71
|
|
|
71
|
|
132
|
my ($self, $f) = @_; |
|
1438
|
71
|
50
|
|
|
|
3082
|
opendir my $fh, $f or return; |
|
1439
|
71
|
|
|
|
|
2314
|
my @content = readdir $fh; |
|
1440
|
71
|
50
|
|
|
|
976
|
closedir $fh or return; |
|
1441
|
71
|
|
|
|
|
701
|
return @content; |
|
1442
|
|
|
|
|
|
|
} |
|
1443
|
|
|
|
|
|
|
|
|
1444
|
|
|
|
|
|
|
sub _read_dir_die { |
|
1445
|
1
|
|
|
1
|
|
3
|
my ($self, $f) = @_; |
|
1446
|
1
|
50
|
|
|
|
57
|
opendir my $fh, $f or die $OS_ERROR; |
|
1447
|
0
|
|
|
|
|
|
my @content = readdir $fh; |
|
1448
|
0
|
0
|
|
|
|
|
closedir $fh or die $OS_ERROR; |
|
1449
|
0
|
|
|
|
|
|
return @content; |
|
1450
|
|
|
|
|
|
|
} |
|
1451
|
|
|
|
|
|
|
|
|
1452
|
|
|
|
|
|
|
1; |
|
1453
|
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
__END__ |