summaryrefslogtreecommitdiff
path: root/ext/Cwd/t/cwd.t
blob: bab3dc372be391004b8e02652f89580aaac5ff44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#!./perl -w

use strict;

use Cwd;

chdir 't';

use Config;
use File::Spec;
use File::Path;

use lib File::Spec->catdir('t', 'lib');
use Test::More;

my $IsVMS = $^O eq 'VMS';
my $IsMacOS = $^O eq 'MacOS';

my $vms_unix_rpt = 0;
my $vms_efs = 0;
my $vms_mode = 0;

if ($IsVMS) {
    require VMS::Filespec;
    use Carp;
    use Carp::Heavy;
    $vms_mode = 1;
    if (eval 'require VMS::Feature') {
        $vms_unix_rpt = VMS::Feature::current("filename_unix_report");
        $vms_efs = VMS::Feature::current("efs_charset");
    } else {
        my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || '';
        my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || '';
        $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i; 
        $vms_efs = $efs_charset =~ /^[ET1]/i; 
    }
    $vms_mode = 0 if ($vms_unix_rpt);
}

my $tests = 30;
# _perl_abs_path() currently only works when the directory separator
# is '/', so don't test it when it won't work.
my $EXTRA_ABSPATH_TESTS = ($Config{prefix} =~ m/\//) && $^O ne 'cygwin';
$tests += 4 if $EXTRA_ABSPATH_TESTS;
plan tests => $tests;

SKIP: {
  skip "no need to check for blib/ in the core", 1 if $ENV{PERL_CORE};
  like $INC{'Cwd.pm'}, qr{blib}i, "Cwd should be loaded from blib/ during testing";
}


# check imports
can_ok('main', qw(cwd getcwd fastcwd fastgetcwd));
ok( !defined(&chdir),           'chdir() not exported by default' );
ok( !defined(&abs_path),        '  nor abs_path()' );
ok( !defined(&fast_abs_path),   '  nor fast_abs_path()');

{
  my @fields = qw(PATH IFS CDPATH ENV BASH_ENV);
  my $before = grep exists $ENV{$_}, @fields;
  cwd();
  my $after = grep exists $ENV{$_}, @fields;
  is($before, $after, "cwd() shouldn't create spurious entries in %ENV");
}

# XXX force Cwd to bootsrap its XSUBs since we have set @INC = "../lib"
# XXX and subsequent chdir()s can make them impossible to find
eval { fastcwd };

# Must find an external pwd (or equivalent) command.

my $pwd = $^O eq 'MSWin32' ? "cmd" : "pwd";
my $pwd_cmd =
    ($^O eq "NetWare") ?
        "cd" :
    ($IsMacOS) ?
        "pwd" :
        (grep { -x && -f } map { "$_/$pwd$Config{exe_ext}" }
	                   split m/$Config{path_sep}/, $ENV{PATH})[0];

$pwd_cmd = 'SHOW DEFAULT' if $IsVMS;
if ($^O eq 'MSWin32') {
    $pwd_cmd =~ s,/,\\,g;
    $pwd_cmd = "$pwd_cmd /c cd";
}
$pwd_cmd =~ s=\\=/=g if ($^O eq 'dos');

SKIP: {
    skip "No native pwd command found to test against", 4 unless $pwd_cmd;

    print "# native pwd = '$pwd_cmd'\n";

    local @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
    my ($pwd_cmd_untainted) = $pwd_cmd =~ /^(.+)$/; # Untaint.
    chomp(my $start = `$pwd_cmd_untainted`);

    # Win32's cd returns native C:\ style
    $start =~ s,\\,/,g if ($^O eq 'MSWin32' || $^O eq "NetWare");
    if ($IsVMS) {
        # DCL SHOW DEFAULT has leading spaces
        $start =~ s/^\s+//;

        # When in UNIX report mode, need to convert to compare it.
        if ($vms_unix_rpt) {
            $start = VMS::Filespec::unixpath($start);
            # Remove trailing slash.
            $start =~ s#/$##;
        }
    }
    SKIP: {
        skip("'$pwd_cmd' failed, nothing to test against", 4) if $?;
        skip("/afs seen, paths unlikely to match", 4) if $start =~ m|/afs/|;

	# Darwin's getcwd(3) (which Cwd.xs:bsd_realpath() uses which
	# Cwd.pm:getcwd uses) has some magic related to the PWD
	# environment variable: if PWD is set to a directory that
	# looks about right (guess: has the same (dev,ino) as the '.'?),
	# the PWD is returned.  However, if that path contains
	# symlinks, the path will not be equal to the one returned by
	# /bin/pwd (which probably uses the usual walking upwards in
	# the path -trick).  This situation is easy to reproduce since
	# /tmp is a symlink to /private/tmp.  Therefore we invalidate
	# the PWD to force getcwd(3) to (re)compute the cwd in full.
	# Admittedly fixing this in the Cwd module would be better
	# long-term solution but deleting $ENV{PWD} should not be
	# done light-heartedly. --jhi
	delete $ENV{PWD} if $^O eq 'darwin';

	my $cwd        = cwd;
	my $getcwd     = getcwd;
	my $fastcwd    = fastcwd;
	my $fastgetcwd = fastgetcwd;

	is($cwd,        $start, 'cwd()');
	is($getcwd,     $start, 'getcwd()');
	is($fastcwd,    $start, 'fastcwd()');
	is($fastgetcwd, $start, 'fastgetcwd()');
    }
}

my @test_dirs = qw{_ptrslt_ _path_ _to_ _a_ _dir_};
my $Test_Dir     = File::Spec->catdir(@test_dirs);

mkpath([$Test_Dir], 0, 0777);
Cwd::chdir $Test_Dir;

foreach my $func (qw(cwd getcwd fastcwd fastgetcwd)) {
  my $result = eval "$func()";
  is $@, '';
  dir_ends_with( $result, $Test_Dir, "$func()" );
}

{
  # Some versions of File::Path (e.g. that shipped with perl 5.8.5)
  # call getcwd() with an argument (perhaps by calling it as a
  # method?), so make sure that doesn't die.
  is getcwd(), getcwd('foo'), "Call getcwd() with an argument";
}

# Cwd::chdir should also update $ENV{PWD}
dir_ends_with( $ENV{PWD}, $Test_Dir, 'Cwd::chdir() updates $ENV{PWD}' );
my $updir = File::Spec->updir;

for (1..@test_dirs) {
  Cwd::chdir $updir;
  print "#$ENV{PWD}\n";
}

rmtree($test_dirs[0], 0, 0);

{
  my $check = ($vms_mode ? qr|\b((?i)t)\]$| :
	       $IsMacOS  ? qr|\bt:$| :
			   qr|\bt$| );
  
  like($ENV{PWD}, $check);
}

{
  # Make sure abs_path() doesn't trample $ENV{PWD}
  my $start_pwd = $ENV{PWD};
  mkpath([$Test_Dir], 0, 0777);
  Cwd::abs_path($Test_Dir);
  is $ENV{PWD}, $start_pwd;
  rmtree($test_dirs[0], 0, 0);
}

SKIP: {
    skip "no symlinks on this platform", 2+$EXTRA_ABSPATH_TESTS unless $Config{d_symlink};

    my $file = "linktest";
    mkpath([$Test_Dir], 0, 0777);
    symlink $Test_Dir, $file;

    my $abs_path      =  Cwd::abs_path($file);
    my $fast_abs_path =  Cwd::fast_abs_path($file);
    my $want          =  quotemeta(
                           File::Spec->rel2abs( $Test_Dir )
                         );
    if ($^O eq 'VMS') {
       # Not easy to predict the physical volume name
       $want = $ENV{PERL_CORE} ? $Test_Dir : File::Spec->catdir('t', $Test_Dir);

       # So just use the relative volume name
       $want =~ s/^\[//;

       $want = quotemeta($want);
    }

    like($abs_path,      qr|$want$|i);
    like($fast_abs_path, qr|$want$|i);
    like(Cwd::_perl_abs_path($file), qr|$want$|i) if $EXTRA_ABSPATH_TESTS;

    rmtree($test_dirs[0], 0, 0);
    1 while unlink $file;
}

if ($ENV{PERL_CORE}) {
    chdir '../ext/Cwd/t';
    unshift @INC, '../../../lib';
}

# Make sure we can run abs_path() on files, not just directories
my $path = 'cwd.t';
path_ends_with(Cwd::abs_path($path), 'cwd.t', 'abs_path() can be invoked on a file');
path_ends_with(Cwd::fast_abs_path($path), 'cwd.t', 'fast_abs_path() can be invoked on a file');
path_ends_with(Cwd::_perl_abs_path($path), 'cwd.t', '_perl_abs_path() can be invoked on a file')
  if $EXTRA_ABSPATH_TESTS;

$path = File::Spec->catfile(File::Spec->updir, 't', $path);
path_ends_with(Cwd::abs_path($path), 'cwd.t', 'abs_path() can be invoked on a file');
path_ends_with(Cwd::fast_abs_path($path), 'cwd.t', 'fast_abs_path() can be invoked on a file');
path_ends_with(Cwd::_perl_abs_path($path), 'cwd.t', '_perl_abs_path() can be invoked on a file')
  if $EXTRA_ABSPATH_TESTS;


  
SKIP: {
  my $file;
  {
    my $root = Cwd::abs_path(File::Spec->rootdir);	# Add drive letter?
    local *FH;
    opendir FH, $root or skip("Can't opendir($root): $!", 2+$EXTRA_ABSPATH_TESTS);
    ($file) = grep {-f $_ and not -l $_} map File::Spec->catfile($root, $_), readdir FH;
    closedir FH;
  }
  skip "No plain file in root directory to test with", 2+$EXTRA_ABSPATH_TESTS unless $file;
  
  $file = VMS::Filespec::rmsexpand($file) if $^O eq 'VMS';
  is Cwd::abs_path($file), $file, 'abs_path() works on files in the root directory';
  is Cwd::fast_abs_path($file), $file, 'fast_abs_path() works on files in the root directory';
  is Cwd::_perl_abs_path($file), $file, '_perl_abs_path() works on files in the root directory'
    if $EXTRA_ABSPATH_TESTS;
}


#############################################
# These routines give us sort of a poor-man's cross-platform
# directory or path comparison capability.

sub bracketed_form_dir {
  return join '', map "[$_]", 
    grep length, File::Spec->splitdir(File::Spec->canonpath( shift() ));
}

sub dir_ends_with {
  my ($dir, $expect) = (shift, shift);
  my $bracketed_expect = quotemeta bracketed_form_dir($expect);
  like( bracketed_form_dir($dir), qr|$bracketed_expect$|i, (@_ ? shift : ()) );
}

sub bracketed_form_path {
  return join '', map "[$_]", 
    grep length, File::Spec->splitpath(File::Spec->canonpath( shift() ));
}

sub path_ends_with {
  my ($dir, $expect) = (shift, shift);
  my $bracketed_expect = quotemeta bracketed_form_path($expect);
  like( bracketed_form_path($dir), qr|$bracketed_expect$|i, (@_ ? shift : ()) );
}