In working with Vanilla Perl on Win32, I keep finding modules that fail their tests due to hardcoded slashes in their test scripts. Even modules that are pretty good about using File::Spec in the module itself seem to slip up during testing. For example:

use Test::More tests => 1; use My::Module qw/get_a_filename/; # gives a path with backslashes my $expected = "some/file/path/here"; is( get_a_filename(), $expected );

I considered writing Test::FilePath that would run arguments through File::Spec->canonpath() automatically:

use Test::FilePath tests => 1; filepath_is( "some/path", "some\path" );

That works for Win32, since canonpath() changes forward-slashes to back-slashes, but I don't think it works for other OSes like MacOS (Classic) that use things like ":" for separators.

Getting a truly platform-independent filepath comparison to a hard-coded test expectation seems like it would require one of these approaches:

  1. Hardcode the path components separately and assemble them at runtime using File::Spec.

    my @expected = qw{ some file path here }; is( get_a_filename(), File::Spec->join( @expected ) );
  2. Use a convention that expected filepaths are always in Unix-style, and use a test helper to split and remap to the local directory separator convention.

    my $expected = "some/file/path/here"; filepath_is( "some:file:path:here", $expected );

Do you prefer one over the other? How have you approached this problem? Are there other ideas you'd suggest? What edge cases do you anticipate? Would you use something like Test::FilePath (despite the extra dependency)?

Your input is greatly appreciated.

P.S. And if you do have hardcoded slashes in some module test on CPAN, please go fix that!

-xdg

Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Replies are listed 'Best First'.
Re: Portable filename comparison for test files
by bobf (Monsignor) on Jul 19, 2006 at 02:49 UTC

    I always use File::Spec for assembling paths (although it isn't a standard practice where I work; I also use File::Temp and File::Copy for added safety and portability, but those modules are outside the scope of the question). Since File::Spec is part of the core distribution I probably wouldn't use a module that creates an extra dependency. Not sure about edge cases, but differences between absolute and relative paths could cause issues if they aren't standardized before comparison.

Re: Portable filename comparison for test files
by Tanktalus (Canon) on Jul 19, 2006 at 02:07 UTC

    From my perspective, either one requires some education of CPAN authors. Thusly educated, the author can make their own decision.

    In my case, I already do 1. Have since nearly the beginning since I've always had to deal with Windows and Unix at the same time, so I've just enforced a coding standard that said "always use File::Spec to create file paths." Hopefully if they ever need to support Mac or something else, it just works. (Then again, since I'm not on that team anymore, it's not entirely my concern anyway ;->)

Re: Portable filename comparison for test files
by Aristotle (Chancellor) on Jul 18, 2006 at 21:12 UTC

    I wouldn’t attach an extra dependency to my code, no. I don’t know that I’m in your target audience though, as the only time I use bare string manipulations to work with paths is in oneliners, so I wouldn’t write my tests without File::Spec anyway.

    Makeshifts last the longest.