view release on metacpan or search on metacpan
lib/App/Cmd.pm view on Meta::CPAN
$self->_prepare_command($self->default_command, $opt, @sub_args);
}
sub _bad_command {
my ($self, $command, $opt, @args) = @_;
print "Unrecognized command: $command.\n\nUsage:\n" if defined($command);
# This should be class data so that, in Bizarro World, two App::Cmds will not
# conflict.
our $_bad++;
$self->prepare_command(qw(commands --stderr));
}
END { exit 1 if our $_bad };
#pod =method default_command
#pod
#pod This method returns the name of the command to run if none is given on the
#pod command line. The default default is "help"
#pod
#pod =cut
lib/App/Cmd/Command/commands.pm view on Meta::CPAN
#pod application's commands and their abstracts.
#pod
#pod The commands are printed in sorted groups (created by C<sort_commands>); each
#pod group is set off by blank lines.
#pod
#pod =cut
sub execute {
my ($self, $opt, $args) = @_;
my $target = $opt->stderr ? *STDERR : *STDOUT;
my @cmd_groups = $self->app->command_groups;
my @primary_commands = map { @$_ if ref $_ } @cmd_groups;
if (!@cmd_groups) {
@primary_commands =
grep { $_ ne 'version' or $self->app->{show_version} }
map { ($_->command_names)[0] }
$self->app->command_plugins;
lib/App/Cmd/Command/commands.pm view on Meta::CPAN
my $float = qr/^(?:help|commands)$/;
my @head = sort grep { $_ =~ $float } @commands;
my @tail = sort grep { $_ !~ $float } @commands;
return (\@head, \@tail);
}
sub opt_spec {
return (
[ 'stderr' => 'hidden' ],
);
}
1;
__END__
=pod
=encoding UTF-8
lib/App/Cmd/Tester.pm view on Meta::CPAN
#pod
#pod use Test::More tests => 4;
#pod use App::Cmd::Tester;
#pod
#pod use YourApp;
#pod
#pod my $result = test_app(YourApp => [ qw(command --opt value) ]);
#pod
#pod like($result->stdout, qr/expected output/, 'printed what we expected');
#pod
#pod is($result->stderr, '', 'nothing sent to sderr');
#pod
#pod is($result->error, undef, 'threw no exceptions');
#pod
#pod my $result = test_app(YourApp => [ qw(command --opt value --quiet) ]);
#pod
#pod is($result->output, '', 'absolutely no output with --quiet');
#pod
#pod =head1 DESCRIPTION
#pod
#pod One of the reasons that user-executed programs are so often poorly tested is
lib/App/Cmd/Tester.pm view on Meta::CPAN
#pod my $result = test_app($app_class => \@argv_contents);
#pod
#pod This will locally set C<@ARGV> to simulate command line arguments, and will
#pod then call the C<run> method on the given application class (or application).
#pod Output to the standard output and standard error filehandles will be captured.
#pod
#pod C<$result> is an App::Cmd::Tester::Result object, which has methods to access
#pod the following data:
#pod
#pod stdout - the output sent to stdout
#pod stderr - the output sent to stderr
#pod output - the combined output of stdout and stderr
#pod error - the exception thrown by running the application, or undef
#pod run_rv - the return value of the run method (generally irrelevant)
#pod exit_code - the numeric exit code that would've been issued (0 is 'okay')
#pod
#pod The output is captured using L<IO::TieCombine>, which I<can> ensure that the
#pod ordering is preserved in the combined output, but I<can't> capture the output
#pod of external programs. You can reverse these tradeoffs by using
#pod L<App::Cmd::Tester::CaptureExternal> instead.
#pod
#pod =cut
lib/App/Cmd/Tester.pm view on Meta::CPAN
});
}
sub _run_with_capture {
my ($class, $app, $argv) = @_;
require IO::TieCombine;
my $hub = IO::TieCombine->new;
my $stdout = tie local *STDOUT, $hub, 'stdout';
my $stderr = tie local *STDERR, $hub, 'stderr';
my $run_rv;
my $ok = eval {
local $TEST_IN_PROGRESS = 1;
local @ARGV = @$argv;
$run_rv = $app->run;
1;
};
my $error = $ok ? undef : $@;
return {
stdout => $hub->slot_contents('stdout'),
stderr => $hub->slot_contents('stderr'),
output => $hub->combined_contents,
error => $error,
run_rv => $run_rv,
};
}
{
package App::Cmd::Tester::Result 0.337;
sub new {
my ($class, $arg) = @_;
bless $arg => $class;
}
for my $attr (qw(app stdout stderr output error run_rv exit_code)) {
Sub::Install::install_sub({
code => sub { $_[0]->{$attr} },
as => $attr,
});
}
}
{
package App::Cmd::Tester::Exited 0.337;
lib/App/Cmd/Tester.pm view on Meta::CPAN
use Test::More tests => 4;
use App::Cmd::Tester;
use YourApp;
my $result = test_app(YourApp => [ qw(command --opt value) ]);
like($result->stdout, qr/expected output/, 'printed what we expected');
is($result->stderr, '', 'nothing sent to sderr');
is($result->error, undef, 'threw no exceptions');
my $result = test_app(YourApp => [ qw(command --opt value --quiet) ]);
is($result->output, '', 'absolutely no output with --quiet');
=head1 DESCRIPTION
One of the reasons that user-executed programs are so often poorly tested is
lib/App/Cmd/Tester.pm view on Meta::CPAN
my $result = test_app($app_class => \@argv_contents);
This will locally set C<@ARGV> to simulate command line arguments, and will
then call the C<run> method on the given application class (or application).
Output to the standard output and standard error filehandles will be captured.
C<$result> is an App::Cmd::Tester::Result object, which has methods to access
the following data:
stdout - the output sent to stdout
stderr - the output sent to stderr
output - the combined output of stdout and stderr
error - the exception thrown by running the application, or undef
run_rv - the return value of the run method (generally irrelevant)
exit_code - the numeric exit code that would've been issued (0 is 'okay')
The output is captured using L<IO::TieCombine>, which I<can> ensure that the
ordering is preserved in the combined output, but I<can't> capture the output
of external programs. You can reverse these tradeoffs by using
L<App::Cmd::Tester::CaptureExternal> instead.
=for Pod::Coverage result_class
lib/App/Cmd/Tester/CaptureExternal.pm view on Meta::CPAN
#pod
#pod use Test::More tests => 4;
#pod use App::Cmd::Tester::CaptureExternal;
#pod
#pod use YourApp;
#pod
#pod my $result = test_app(YourApp => [ qw(command --opt value) ]);
#pod
#pod like($result->stdout, qr/expected output/, 'printed what we expected');
#pod
#pod is($result->stderr, '', 'nothing sent to sderr');
#pod
#pod ok($result->output, "STDOUT concatenated with STDERR");
#pod
#pod =head1 DESCRIPTION
#pod
#pod L<App::Cmd::Tester> provides a useful scaffold for testing applications, but it
#pod is unable to capture output generated from any external subprograms that are
#pod invoked from the application.
#pod
#pod This subclass uses an alternate mechanism for capturing output
lib/App/Cmd/Tester/CaptureExternal.pm view on Meta::CPAN
#pod testing if something appeared in either output stream, but you can't rely on
#pod the ordering being correct between lines to STDOUT and lines to STDERR.
#pod
#pod =cut
sub _run_with_capture {
my ($class, $app, $argv) = @_;
my $run_rv;
my ($stdout, $stderr, $ok) = capture {
eval {
local $App::Cmd::Tester::TEST_IN_PROGRESS = 1;
local @ARGV = @$argv;
$run_rv = $app->run;
1;
};
};
my $error = $ok ? undef : $@;
return {
stdout => $stdout,
stderr => $stderr,
output => $stdout . $stderr,
error => $error,
run_rv => $run_rv,
};
}
1;
__END__
=pod
lib/App/Cmd/Tester/CaptureExternal.pm view on Meta::CPAN
use Test::More tests => 4;
use App::Cmd::Tester::CaptureExternal;
use YourApp;
my $result = test_app(YourApp => [ qw(command --opt value) ]);
like($result->stdout, qr/expected output/, 'printed what we expected');
is($result->stderr, '', 'nothing sent to sderr');
ok($result->output, "STDOUT concatenated with STDERR");
=head1 DESCRIPTION
L<App::Cmd::Tester> provides a useful scaffold for testing applications, but it
is unable to capture output generated from any external subprograms that are
invoked from the application.
This subclass uses an alternate mechanism for capturing output
#!perl
use strict;
use warnings;
use Test::More 'no_plan';
use Capture::Tiny 'capture_stderr';
use lib 't/lib';
my $CLASS = 'Test::WithSetup';
require_ok($CLASS);
ok($CLASS->isa('App::Cmd'), "$CLASS subclasses App::Cmd");
my $app = $CLASS->new;
is_deeply(
$return,
{},
"basically run",
);
}
{
local @ARGV = qw(alfie --why);
my ($stderr, $return) = capture_stderr(sub {
eval { $app->run }
});
is_deeply(
$return,
undef,
"unknown option with overridden getopt_conf caused program to exit",
);
like(
$stderr,
qr{Unknown option: why},
"and gives the standard G::L::D missing option message",
);
}
{
local @ARGV = qw(bertie);
my $return = eval { $app->run };
is($return->[0], 'Test::XyzzyPlugin', "arg0 = plugin itself");
t/tester-exit.t view on Meta::CPAN
use Capture::Tiny 'capture';
use File::Spec;
require App::Cmd::Tester; # not used, but check which!
my $helper_fn = $0;
$helper_fn =~ s{\.t$}{.helper.pl} or die "Can't make helper from $0";
for my $exit_with (0, 5) {
my ($stdout, $stderr, $got_exit) = capture {
system(
$^X,
(-d 'blib' ? '-Mblib' : ('-I', File::Spec->rel2abs('lib'))),
$helper_fn, $exit_with);
};
chomp $stdout;
is($stdout, $INC{'App/Cmd/Tester.pm'}, "App::Cmd::Tester source path")
unless $exit_with; # just once