our
$VERSION
=
'0.08'
;
our
@EXPORT
=
qw/run_ok run_not_ok run_script run_output_matches run_output_matches_unordered/
;
our
@EXPORT_OK
=
qw/is_script_output last_script_stdout last_script_stderr
last_script_exit_code get_perl_cmd/
;
our
%EXPORT_TAGS
= (
all
=> [
@EXPORT
,
@EXPORT_OK
] );
my
(
$last_script_stdout
,
$last_script_stderr
,
$last_script_exit_code
,
);
our
@BIN_DIRS
= (
'bin'
,
'sbin'
,
'script'
,
'.'
);
sub
run_script {
my
$script
=
shift
;
my
$args
=
shift
|| [];
my
(
$stdout
,
$stderr
) =
@_
;
my
(
$new_stdout
,
$new_stderr
,
$return_stdouterr
);
if
( !
ref
(
$stdout
) && !
ref
(
$stderr
) ) {
(
$stdout
,
$stderr
,
$return_stdouterr
) =
( \
$new_stdout
, \
$new_stderr
, 1 );
}
my
@cmd
= get_perl_cmd(
$script
);
if
(
@cmd
) {
my
$ret
= run3 [
@cmd
,
@$args
],
undef
,
$stdout
,
$stderr
;
$last_script_exit_code
= $? >> 8;
if
(
ref
$stdout
eq
'SCALAR'
) {
$last_script_stdout
=
$$stdout
;
}
if
(
ref
$stderr
eq
'SCALAR'
) {
$last_script_stderr
=
$$stderr
;
}
return
$return_stdouterr
? (
$ret
,
$last_script_stdout
,
$last_script_stderr
)
:
$ret
;
}
else
{
$last_script_exit_code
= 127;
return
;
}
}
sub
run_ok {
return
_run_ok(
'=='
,
@_
);
}
sub
run_not_ok {
return
_run_ok(
'!='
,
@_
);
}
sub
_run_ok {
my
$cmp
=
shift
||
'=='
;
my
$script
=
shift
;
my
$args
;
$args
=
shift
if
(
ref
$_
[0] eq
'ARRAY'
);
my
$msg
= (
@_
) ?
shift
:
''
;
local
$Test::Builder::Level
=
$Test::Builder::Level
+ 1;
lives_and {
local
$Test::Builder::Level
=
$Test::Builder::Level
+ 1;
my
(
$ret
,
$stdout
,
$stderr
) = run_script(
$script
,
$args
);
cmp_ok(
$last_script_exit_code
,
$cmp
, 0, _generate_test_name(
$msg
,
$script
,
@$args
) );
};
}
sub
_updir {
my
$path
=
shift
;
my
(
$file
,
$dir
,
undef
) = fileparse( File::Spec->rel2abs(
$path
) );
return
$dir
;
}
our
$RUNCNT
;
sub
get_perl_cmd {
my
$script
=
shift
;
my
$base_dir
;
if
(
defined
$script
) {
my
$fail
= 0;
if
( File::Spec->file_name_is_absolute(
$script
) ) {
unless
( -f
$script
) {
warn
"couldn't find the script $script"
;
$fail
= 1;
}
}
else
{
my
(
$tmp
,
$i
) = ( _updir($0), 0 );
my
$found
;
LOOP:
while
(
$i
++ < 10 ) {
for
my
$bin
(
@BIN_DIRS
) {
if
( -f File::Spec->catfile(
$tmp
,
$bin
,
$script
) ) {
$script
= File::Spec->catfile(
$tmp
,
$bin
,
$script
);
$found
= 1;
last
LOOP;
}
}
$tmp
= _updir(
$tmp
);
}
unless
(
$found
) {
warn
"couldn't find the script $script"
;
$fail
= 1;
}
}
return
if
$fail
;
}
my
@cmd
= ( $^X, (
map
{
"-I$_"
}
grep
{!
ref
(
$_
)}
@INC
) );
push
@cmd
,
'-MDevel::Cover'
if
$INC
{
'Devel/Cover.pm'
};
if
(
$INC
{
'Devel/DProf.pm'
} ) {
push
@cmd
,
'-d:DProf'
;
$ENV
{
'PERL_DPROF_OUT_FILE_NAME'
} =
'tmon.out.'
. $$ .
'.'
.
$RUNCNT
++;
}
if
(
defined
$script
) {
push
@cmd
,
$script
;
push
@cmd
,
@_
;
}
return
@cmd
;
}
*_get_perl_cmd
= \
&get_perl_cmd
;
sub
is_script_output {
my
(
$script
,
$args
,
$exp_stdout
,
$exp_stderr
,
$msg
) =
@_
;
local
$Test::Builder::Level
=
$Test::Builder::Level
+ 1;
my
$stdout_err
= [];
$exp_stderr
||= [];
my
$ret
= run_script(
$script
,
$args
,
_mk_cmp_closure(
'stdout'
,
$exp_stdout
,
$stdout_err
),
_mk_cmp_closure(
'stderr'
,
$exp_stderr
,
$stdout_err
),
);
_check_cmp_closure_output(
$script
,
$msg
,
$args
,
$exp_stdout
,
$stdout_err
);
}
sub
_mk_cmp_closure {
my
(
$type
,
$exp
,
$err
) =
@_
;
if
(
$type
eq
'stderr'
) {
$last_script_stderr
=
''
;
my
$line
= 0;
return
sub
{
my
$output
=
shift
;
++
$line
;
$last_script_stderr
.=
$output
;
__mk_cmp_closure()->(
$exp
,
$err
,
$line
,
$output
);
}
}
else
{
$last_script_stdout
=
''
;
my
$line
= 0;
return
sub
{
my
$output
=
shift
;
++
$line
;
$last_script_stdout
.=
$output
;
__mk_cmp_closure()->(
$exp
,
$err
,
$line
,
$output
);
}
}
}
sub
__mk_cmp_closure {
sub
{
my
(
$exp
,
$err
,
$line
,
$output
) =
@_
;
chomp
$output
;
unless
(
@$exp
) {
push
@$err
,
"$line: got $output"
;
return
;
}
my
$item
=
shift
@$exp
;
push
@$err
,
"$line: got ($output), expect ($item)\n"
unless
ref
(
$item
) eq
'Regexp'
? (
$output
=~ m/
$item
/ )
: (
$output
eq
$item
);
}
}
sub
_check_cmp_closure_output {
my
(
$script
,
$msg
,
$args
,
$exp_stdout
,
$stdout_err
) =
@_
;
for
my
$line
(
@$exp_stdout
) {
next
if
!
defined
$line
;
push
@$stdout_err
,
"got nothing, expected: $line"
;
}
my
$test_name
= _generate_test_name(
$msg
,
$script
,
@$args
);
is(
scalar
(
@$stdout_err
), 0,
$test_name
);
if
(
@$stdout_err
) {
diag(
"Different in line: "
.
join
(
"\n"
,
@$stdout_err
) );
}
}
sub
run_output_matches {
my
(
$script
,
$args
,
$expected
,
$stderr
,
$msg
) =
@_
;
local
$Test::Builder::Level
=
$Test::Builder::Level
+ 1;
lives_and {
local
$Test::Builder::Level
=
$Test::Builder::Level
+ 5;
is_script_output(
$script
,
$args
,
$expected
,
$stderr
,
$msg
);
};
}
sub
run_output_matches_unordered {
my
(
$cmd
,
$args
,
$stdout
,
$stderr
,
$msg
) =
@_
;
$stderr
||= [];
my
(
$val
,
$out
,
$err
) = run_script(
$cmd
,
$args
);
local
$Test::Builder::Level
=
$Test::Builder::Level
+ 1;
my
$errors
= [];
my
@lines
=
split
/\n/,
$out
;
OUTPUT:
while
(
my
$line
=
shift
@lines
) {
for
my
$exp_line
(
@$stdout
) {
if
(
(
ref
(
$exp_line
) eq
'Regexp'
? (
$line
=~ m/
$exp_line
/ )
: (
$line
eq
$exp_line
)
)
)
{
$stdout
= [
grep
{
$_
ne
$exp_line
}
@$stdout
];
next
OUTPUT;
}
}
push
@$errors
,
"couldn't find match for ($line)\n"
;
}
@lines
=
split
/\n/,
$err
;
ERROR:
while
(
my
$line
=
shift
@lines
) {
for
my
$exp_line
(
@$stderr
) {
if
(
(
ref
(
$exp_line
) eq
'Regexp'
? (
$line
=~ m/
$exp_line
/ )
: (
$line
eq
$exp_line
)
)
)
{
$stderr
= [
grep
{
$_
ne
$exp_line
}
@$stderr
];
next
ERROR;
}
}
push
@$errors
,
"couldn't find match for ($line)\n"
;
}
for
my
$exp_line
(
@$stdout
,
@$stderr
) {
push
@$errors
,
"got nothing, expected: $exp_line"
;
}
my
$test_name
= _generate_test_name(
$msg
,
$cmd
,
@$args
);
is(
scalar
(
@$errors
), 0,
$test_name
);
if
(
@$errors
) {
diag(
"Errors: "
.
join
(
"\n"
,
@$errors
) );
}
}
sub
_is_windows {
return
$^O =~ /MSWin/;
}
sub
_generate_test_name {
my
$msg
=
shift
;
my
$script
=
shift
;
my
@args
=
@_
;
my
$args
;
if
( _is_windows() ) {
if
($@) {
$args
=
join
' '
,
@_
;
}
else
{
$args
= Win32::ShellQuote::quote_system_string(
@_
);
}
}
else
{
if
($@) {
$args
=
join
' '
,
@_
;
}
else
{
$args
= String::ShellQuote::shell_quote(
@_
);
}
}
return
join
(
' '
,
$msg
?
"$msg:"
: (),
$script
,
defined
$args
&&
length
$args
?
$args
: () );
}
sub
last_script_stdout {
$last_script_stdout
}
sub
last_script_stderr {
$last_script_stderr
}
sub
last_script_exit_code {
$last_script_exit_code
}
1;