xref: /openbsd-src/gnu/usr.bin/perl/t/op/filetest.t (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1#!./perl
2
3# There are few filetest operators that are portable enough to test.
4# See pod/perlport.pod for details.
5
6BEGIN {
7    chdir 't' if -d 't';
8    @INC = '../lib';
9    require './test.pl';
10}
11
12use Config;
13plan(tests => 28 + 27*14);
14
15ok( -d 'op' );
16ok( -f 'TEST' );
17ok( !-f 'op' );
18ok( !-d 'TEST' );
19ok( -r 'TEST' );
20
21# Make a read only file
22my $ro_file = tempfile();
23
24{
25    open my $fh, '>', $ro_file or die "open $fh: $!";
26    close $fh or die "close $fh: $!";
27}
28
29chmod 0555, $ro_file or die "chmod 0555, '$ro_file' failed: $!";
30
31$oldeuid = $>;		# root can read and write anything
32eval '$> = 1';		# so switch uid (may not be implemented)
33
34print "# oldeuid = $oldeuid, euid = $>\n";
35
36SKIP: {
37    if (!$Config{d_seteuid}) {
38	skip('no seteuid');
39    }
40    else {
41	ok( !-w $ro_file );
42    }
43}
44
45# Scripts are not -x everywhere so cannot test that.
46
47eval '$> = $oldeuid';	# switch uid back (may not be implemented)
48
49# this would fail for the euid 1
50# (unless we have unpacked the source code as uid 1...)
51ok( -r 'op' );
52
53# this would fail for the euid 1
54# (unless we have unpacked the source code as uid 1...)
55SKIP: {
56    if ($Config{d_seteuid}) {
57	ok( -w 'op' );
58    } else {
59	skip('no seteuid');
60    }
61}
62
63ok( -x 'op' ); # Hohum.  Are directories -x everywhere?
64
65is( "@{[grep -r, qw(foo io noo op zoo)]}", "io op" );
66
67# Test stackability of filetest operators
68
69ok( defined( -f -d 'TEST' ) && ! -f -d _ );
70ok( !defined( -e 'zoo' ) );
71ok( !defined( -e -d 'zoo' ) );
72ok( !defined( -f -e 'zoo' ) );
73ok( -f -e 'TEST' );
74ok( -e -f 'TEST' );
75ok( defined(-d -e 'TEST') );
76ok( defined(-e -d 'TEST') );
77ok( ! -f -d 'op' );
78ok( -x -d -x 'op' );
79ok( (-s -f 'TEST' > 1), "-s returns real size" );
80ok( -f -s 'TEST' == 1 );
81
82# now with an empty file
83my $tempfile = tempfile();
84open my $fh, ">", $tempfile;
85close $fh;
86ok( -f $tempfile );
87is( -s $tempfile, 0 );
88is( -f -s $tempfile, 0 );
89is( -s -f $tempfile, 0 );
90unlink $tempfile;
91
92# test that _ is a bareword after filetest operators
93
94-f 'TEST';
95ok( -f _ );
96sub _ { "this is not a file name" }
97ok( -f _ );
98
99my $over;
100{
101    package OverFtest;
102
103    use overload
104	fallback => 1,
105        -X => sub {
106            $over = [qq($_[0]), $_[1]];
107            "-$_[1]";
108        };
109}
110{
111    package OverString;
112
113    # No fallback. -X should fall back to string overload even without
114    # it.
115    use overload q/""/ => sub { $over = 1; "TEST" };
116}
117{
118    package OverBoth;
119
120    use overload
121        q/""/   => sub { "TEST" },
122        -X      => sub { "-$_[1]" };
123}
124{
125    package OverNeither;
126
127    # Need fallback. Previous versions of perl required 'fallback' to do
128    # -X operations on an object with no "" overload.
129    use overload
130        '+' => sub { 1 },
131        fallback => 1;
132}
133
134my $ft = bless [], "OverFtest";
135my $ftstr = qq($ft);
136my $str = bless [], "OverString";
137my $both = bless [], "OverBoth";
138my $neither = bless [], "OverNeither";
139my $nstr = qq($neither);
140
141open my $gv, "<", "TEST";
142bless $gv, "OverString";
143open my $io, "<", "TEST";
144$io = *{$io}{IO};
145bless $io, "OverString";
146
147my $fcntl_not_available;
148eval { require Fcntl } or $fcntl_not_available = 1;
149
150for my $op (split //, "rwxoRWXOezsfdlpSbctugkTMBAC") {
151    $over = [];
152    ok( my $rv = eval "-$op \$ft",  "overloaded -$op succeeds" )
153        or diag( $@ );
154    is( $over->[0], $ftstr,         "correct object for overloaded -$op" );
155    is( $over->[1], $op,            "correct op for overloaded -$op" );
156    is( $rv,        "-$op",         "correct return value for overloaded -$op");
157
158    my ($exp, $is) = (1, "is");
159    if (
160	!$fcntl_not_available and (
161        $op eq "u" and not eval { Fcntl::S_ISUID() } or
162        $op eq "g" and not eval { Fcntl::S_ISGID() } or
163        $op eq "k" and not eval { Fcntl::S_ISVTX() }
164	)
165    ) {
166        ($exp, $is) = (0, "not");
167    }
168
169    $over = 0;
170    $rv = eval "-$op \$str";
171    ok( !$@,                        "-$op succeeds with string overloading" )
172        or diag( $@ );
173    is( $rv, eval "-$op 'TEST'",    "correct -$op on string overload" );
174    is( $over,      $exp,           "string overload $is called for -$op" );
175
176    ($exp, $is) = $op eq "l" ? (1, "is") : (0, "not");
177
178    $over = 0;
179    eval "-$op \$gv";
180    is( $over,      $exp,   "string overload $is called for -$op on GLOB" );
181
182    # IO refs always get string overload called. This might be a bug.
183    $op eq "t" || $op eq "T" || $op eq "B"
184        and ($exp, $is) = (1, "is");
185
186    $over = 0;
187    eval "-$op \$io";
188    is( $over,      $exp,   "string overload $is called for -$op on IO");
189
190    $rv = eval "-$op \$both";
191    is( $rv,        "-$op",         "correct -$op on string/-X overload" );
192
193    $rv = eval "-$op \$neither";
194    ok( !$@,                        "-$op succeeds with random overloading" )
195        or diag( $@ );
196    is( $rv, eval "-$op \$nstr",    "correct -$op with random overloading" );
197
198    is( eval "-r -$op \$ft", "-r",      "stacked overloaded -$op" );
199    is( eval "-$op -r \$ft", "-$op",    "overloaded stacked -$op" );
200}
201