Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

How do I test a script that doesn't have a .pl extension

by ten8ciousb (Novice)
on Nov 02, 2012 at 01:02 UTC ( [id://1001895]=perlquestion: print w/replies, xml ) Need Help??

ten8ciousb has asked for the wisdom of the Perl Monks concerning the following question:

writing tests for perl scripts that are part of a larger application. for historical reasons, the scripts do not have a .pl extension. using Test::More
the file I want to test is located in a relative directory "/source/bin"
I'm trying

unshift @INC, '/source/bin'; require_ok('foo')

but I get the error message:

not ok 1 - require foo; # Tried to require 'foo'. # Error: Can't locate foo.pm in @INC (@INC contains: /source/bin +(blah, blah, blah) at (eval 6) line 2.

maybe the more important question is "can I 'require' a script without a '.pl' extension?" because if I change it to foo.pl the test works. but again, for historical reasons, the scripts do not have extensions and changing that would require more refactoring than I can do (at this time)

Replies are listed 'Best First'.
Re: How do I test a script that doesn't have a .pl extension
by tobyink (Canon) on Nov 02, 2012 at 06:42 UTC

    require_ok does two things - it requires modules by filename ("Foo/Bar.pm"), and requires modules by module name ("Foo::Bar").

    It uses heuristics to figure out what you're trying to do. If it sees a dot or a slash in the string you give it, it assumes a filename. If it sees a double-colon, then it assumes a module name. (Actually, I'm simplifying; it uses a couple of interesting regexps, but for practical purposes, let's assume that what I've said is the case.) Your string has neither, so it's taking a wild stab in the dark and assuming a module name, not a filename.

    Untested, but require_ok("./foo") might do the trick.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
      Nope, ./ breaks the searching of @INC, "foo\0" doesn't
Re: How do I test a script that doesn't have a .pl extension
by kielstirling (Scribe) on Nov 02, 2012 at 02:25 UTC
    Hi, works for me. try putting the path to the file in the require ie...
    require '/path/to/file/';
      yes require 'foo' works, but require_ok(foo) fails. that is what threw me.
      I'm trying to add a suite of tests that can go from server to server, OS to OS. the full path will not always be the same. and the tests are not all at the same directory level.
      I am actually using a BEGIN block which finds a common ancestor directory and then builds the lib path from there.
      further testing has shown that even if foo is in the test directory, require_ok(foo) doesn't work
Re: How do I test a script that doesn't have a .pl extension
by Anonymous Monk on Nov 02, 2012 at 03:13 UTC
    So require_ok is broken :) Try ok( require '...' );

      well this is embarassing. first time seeking wisdom and, er... how does that go?
      TMTOWTDI
      yes.

      require_ok('foo') ### fails foo not found in @INC ok(require 'foo') ### passes
      did work for me. thank you.

        That test will crash instead of failing, if foo does not exist, or is empty:

        >perl -MTest::More=tests,2 -e "ok(require 'empty.pl'); print ok 1" 1..2 empty.pl did not return a true value at -e line 1. # Looks like your test exited with 255 before it could output anything +.
        Q:\>perl -MTest::More=tests,2 -e "ok(require 'nonexistent.pl'); print +ok 1" 1..2 Can't locate nonexistent.pl in @INC (@INC contains: ...) at -e line 1. # Looks like your test exited with 2 before it could output anything.

        You may want to let your tests just crash, because in my experience, use_ok and require_ok are just useless anyway, as no subsequent test will pass if they fail.

      Update: stepped through the execution and found why it fails.
      In require_ok
      # Try to determine if we've been given a module name or file. # Module names must be barewords, files not. $module = qq['$module'] unless _is_module_name($module);
      the problem is in _is_module_name
      foo is being treated as a module because of this
      $module =~ s/\b::\b//g; return $module =~ /^[a-zA-Z]\w*$/ ? 1 : 0;
      with "foo.pl" it returns 0
      with "foo" it returns 1
      changing it to
      # $module =~ s/\b::\b//g; return $module =~ /^[a-zA-Z]\w*$/ ? 1 : 0 if $module =~ s/\b::\b//g;
      resolves the problem and works for these tested scenarios
      require_ok("foo"); require_ok('foo'); require_ok("foo.pl"); require_ok('foo.pl'); require_ok("Net::FTP"); require_ok('Net::FTP');
Re: How do I test a script that doesn't have a .pl extension
by Khen1950fx (Canon) on Nov 02, 2012 at 03:41 UTC
    I used Module::Loaded:
    #!/usr/bin/perl BEGIN { $| = 1; $^W = 1; eval { use strict; use warnings; use Module::Loaded; my $script = mark_as_loaded('foo'); my $loc = is_loaded('foo'); }; } use strict; use warnings; use Module::Loaded; use Test::More tests => 1; require foo; require_ok('foo');

      I used Module::Loaded

      You failed. A .pl file is not a module, you shouldn't treat it as a module.

Re: How do I test a script that doesn't have a .pl extension
by Anonymous Monk on Nov 02, 2012 at 06:55 UTC

    This seems to work require_ok("foo\0");

    As does use lib 'source'; require_ok('bin/foo');

    Both \0 and / signal to require_ok that you're looking to require a file ( as in require_ok_file or require_ok_expr, not require_bareword )

      Just as a heads-up, I expect Perl to issue a warning (or maybe even a fatal error, maybe with taint) in the future when it is told to open a file from a scalar containing a \0. This is under the assumption that most such usage is malicious, for example to circumvent naïve "filename" validation like the following:

      # Read (malicious) filename from user, over the web: $filename = "/etc/passwd\0.jpg"; # Verify it's a .jpg file: $filename =~ /\.jpg$/ or return; # Verify it exists: -f $filename or return; # Output the file to the user: send_file( $filename );
      thank you. yes. this also works.
      one note to future Seekers:
      you need the "", not ''
      require_ok('foo\0'); ### it no work require_ok("foo\0"); ### passes

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1001895]
Approved by Athanasius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (4)
As of 2024-04-19 23:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found