After getting side-tracked, trying to fix a hard-coded path in a test file, and finally succeeding, I thought for moment that cpanm Dancer2
would now work without problems. But, alas, it was not to be. Only, this time, the failure was a real WTF moment:
# Failed test 'Default caller' # at t/classes/Dancer2-Core-Role-HasLocation/with.t line 31. # got: 't/classes/Dancer2-Core-Role-HasLocation/with.t' # expected: 't\classes\Dancer2-Core-Role-HasLocation\with.t' # Looks like you failed 1 test of 11.
Look carefully, and you may notice that the expected string has the correct directory separators.
Why is that?
After all, the test file uses File::Spec->catfile
:
my $path = File::Spec->catfile(qw<
t classes Dancer2-Core-Role-HasLocation with.t
>);
is( $app->caller, $path, 'Default caller' );
For some reason, $app->caller
is returning Unix style directory separators. Finding the reason took some time. caller
in Dancer2::Core::Role::HasLocation looks innocuous enough. Further more, there are numerous calls to File::Spec
methods from Dancer2::Core::Role::HasLocation::_build_location
.
It looks like we must go in to Dancer2::FileUtils.
Looking at that module, we see:
sub path {
my @parts = @_;
my $path = File::Spec->catfile(@parts);
return normalize_path($path);
}
So, we use catfile
to build the path … But, then, what is this normalize_path
?
Ya da ya da … That wasn’t leading anywhere.
So, I did:
C:\…\Dancer2-0.155001> prove -vb t\classes\Dancer2-Core-Role-HasLocation\with.t
t\classes\Dancer2-Core-Role-HasLocation\with.t ..
1..11
# Defaults:
ok 1 - An object of class 'App' isa 'App'
ok 2 - App->can(...)
ok 3 - App->can('_build_location')
ok 4 - App consumes Dancer2::Core::Role::HasLocation
ok 5 - Default caller
# With lib/ and bin/:
ok 6 - An object of class 'App' isa 'App'
ok 7 - Got correct location with lib/ and bin/
# With .dancer file:
ok 8 - An object of class 'App' isa 'App'
ok 9 - Got correct location with .dancer file
# blib/ ignored:
ok 10 - An object of class 'App' isa 'App'
ok 11 - blib/ dir is ignored
ok
All tests successful.
Files=1, Tests=11, 1 wallclock secs ( 0.14 usr + 0.01 sys = 0.16 CPU)
Result: PASS
Looks perfect.
What could be the problem?
Let’s try Build test
:
t/classes/Dancer2-Core-Role-Handler/with.t ............ ok
t/classes/Dancer2-Core-Role-HasLocation/with.t ........ 1/11
# Failed test 'Default caller'
# at t/classes/Dancer2-Core-Role-HasLocation/with.t line 31.
# got: 't/classes/Dancer2-Core-Role-HasLocation/with.t'
# expected: 't\classes\Dancer2-Core-Role-HasLocation\with.t'
# Looks like you failed 1 test of 11.
After a lot of squinting, I believe the problem lies in Module::Build::Base::rscan_dir
. Everything else takes great care to use File::Spec
whereas rscandir
just takes whatever File::Find gives it.
File::Find
has always returned Unix style paths:
C:\&hellip\Dancer2-0.155001> perl -MFile::Find -E "find(sub { say $File::Find::name }, 't')"
…
t/classes/Dancer2-Core-Role-Engine/with.t
t/classes/Dancer2-Core-Role-Handler
t/classes/Dancer2-Core-Role-Handler/with.t
t/classes/Dancer2-Core-Role-HasLocation
t/classes/Dancer2-Core-Role-HasLocation/with.t
t/classes/Dancer2-Core-Role-HasLocation/FakeDancerDir
…
The real fix should go into Module::Build
. In terms of defensive programming, however, the test in Dancer2 can be fixed by using File::Spec->canonpath
:
my $path = File::Spec->catfile(qw<
t classes Dancer2-Core-Role-HasLocation with.t
>);
is(
File::Spec->canonpath($app->caller),
$path,
'Default caller'
);
PS: See also Dancer2 issue #679.