CLI-Simple
view release on metacpan or search on metacpan
t/cli-simple-selective-roles.t view on Meta::CPAN
use strict;
use warnings;
use File::Temp qw(tempfile);
use Test::More;
use CLI::Simple;
########################################################################
sub write_manifest {
########################################################################
my ($yaml) = @_;
my ( $fh, $filename ) = tempfile();
print {$fh} $yaml;
close $fh;
return $filename;
}
########################################################################
subtest 'single selective role' => sub {
########################################################################
{
package Local::Role::Foo;
use Role::Tiny;
sub cmd_foo {
return 'foo';
}
}
{
package Local::Role::Bar;
use Role::Tiny;
sub cmd_bar {
return 'bar';
}
}
{
package Local::App::Single;
use parent qw(CLI::Simple);
}
my $manifest = write_manifest(<<'YAML');
---
roles:
foo: Local::Role::Foo
bar: Local::Role::Bar
YAML
local @ARGV = qw(foo);
CLI::Simple->_load_manifest( 'Local::App::Single', $manifest );
is( Local::App::Single->main, 'foo', 'selective role command runs' );
ok( Local::App::Single->can('cmd_foo'), 'selected role was composed' );
ok( !Local::App::Single->can('cmd_bar'), 'unselected role was not composed' );
return;
};
########################################################################
subtest 'multiple roles for one command' => sub {
########################################################################
{
package Local::Role::Packages;
use Role::Tiny;
sub package_name {
return 'Foo-Bar';
}
}
{
package Local::Role::Publish;
use Role::Tiny;
sub cmd_publish {
my ($self) = @_;
return $self->package_name;
}
}
{
package Local::App::Multiple;
use parent qw(CLI::Simple);
}
my $manifest = write_manifest(<<'YAML');
---
roles:
publish:
- Local::Role::Publish
- Local::Role::Packages
YAML
local @ARGV = qw(publish);
CLI::Simple->_load_manifest( 'Local::App::Multiple', $manifest );
is( Local::App::Multiple->main, 'Foo-Bar', 'all roles required by command are composed' );
ok( Local::App::Multiple->can('cmd_publish'), 'command role was composed' );
ok( Local::App::Multiple->can('package_name'), 'supporting role was composed' );
return;
};
########################################################################
subtest 'legacy command selection composes all legacy roles' => sub {
########################################################################
{
package Local::Role::LegacyFoo;
use Role::Tiny;
sub cmd_foo {
return 'foo';
}
}
{
package Local::Role::LegacyBar;
use Role::Tiny;
sub cmd_bar {
return 'bar';
}
}
{
package Local::App::Legacy;
use parent qw(CLI::Simple);
}
my $manifest = write_manifest(<<'YAML');
---
commands:
foo: Local::Role::LegacyFoo
bar: Local::Role::LegacyBar
YAML
local @ARGV = qw(foo);
CLI::Simple->_load_manifest( 'Local::App::Legacy', $manifest );
ok( !Local::App::Legacy->can('cmd_foo'), 'legacy selected role not composed during manifest load', );
ok( !Local::App::Legacy->can('cmd_bar'), 'legacy unselected role not composed during manifest load', );
is( Local::App::Legacy->main, 'foo', 'legacy command still runs', );
ok( Local::App::Legacy->can('cmd_foo'), 'legacy selected role composed after selecting legacy command', );
ok( Local::App::Legacy->can('cmd_bar'), 'all legacy roles composed after selecting legacy command', );
return;
};
########################################################################
subtest 'abbreviation resolves before selective composition' => sub {
########################################################################
{
package Local::Role::PublishLong;
use Role::Tiny;
sub cmd_publish_to_cpan {
return 'published';
}
}
{
package Local::App::Abbreviation;
use parent qw(CLI::Simple);
}
my $manifest = write_manifest(<<'YAML');
---
roles:
publish-to-cpan: Local::Role::PublishLong
abbreviations: 1
YAML
local @ARGV = qw(publish-to);
CLI::Simple->_load_manifest( 'Local::App::Abbreviation', $manifest );
is( Local::App::Abbreviation->main, 'published', 'abbreviation resolves to selective command' );
ok( Local::App::Abbreviation->can('cmd_publish_to_cpan'), 'canonical command role was composed' );
return;
};
########################################################################
subtest 'command alias uses canonical selective command' => sub {
########################################################################
{
package Local::Role::PublishAlias;
use Role::Tiny;
sub cmd_publish_to_cpan {
return 'published';
}
}
{
package Local::App::Alias;
use parent qw(CLI::Simple);
}
my $manifest = write_manifest(<<'YAML');
---
roles:
publish-to-cpan: Local::Role::PublishAlias
alias:
commands:
pub: publish-to-cpan
YAML
local @ARGV = qw(pub);
CLI::Simple->_load_manifest( 'Local::App::Alias', $manifest );
is( Local::App::Alias->main, 'published', 'alias dispatches to canonical selective command' );
ok( Local::App::Alias->can('cmd_publish_to_cpan'), 'canonical command method was composed' );
ok !Local::App::Alias->can('cmd_pub'), 'alias does not require a separate command method';
return;
};
########################################################################
subtest 'command cannot appear in commands and roles' => sub {
########################################################################
{
package Local::App::Duplicate;
use parent qw(CLI::Simple);
}
my $manifest = write_manifest(<<'YAML');
---
commands:
foo: Local::Role::Foo
roles:
foo: Local::Role::Foo
YAML
eval { CLI::Simple->_load_manifest( 'Local::App::Duplicate', $manifest ); };
like( $@, qr/command 'foo' is defined in both commands and roles/, 'duplicate command definition rejected' );
return;
};
########################################################################
subtest 'invalid selective role specification' => sub {
########################################################################
{
package Local::App::InvalidSpec;
use parent qw(CLI::Simple);
}
my $manifest = write_manifest(<<'YAML');
---
roles:
foo:
role: Local::Role::Foo
YAML
eval { CLI::Simple->_load_manifest( 'Local::App::InvalidSpec', $manifest ); };
like( $@, qr/invalid roles specification for command 'foo'/, 'non-scalar and non-array role specification rejected' );
return;
};
########################################################################
subtest 'selected roles must implement command' => sub {
########################################################################
{
package Local::Role::NoCommand;
use Role::Tiny;
sub something_else {
return 'nope';
}
}
{
package Local::App::MissingCommand;
use parent qw(CLI::Simple);
}
my $manifest = write_manifest(<<'YAML');
---
roles:
foo: Local::Role::NoCommand
YAML
local @ARGV = qw(foo);
CLI::Simple->_load_manifest( 'Local::App::MissingCommand', $manifest );
eval { Local::App::MissingCommand->main; };
like( $@, qr/roles for command 'foo' do not implement cmd_foo/, 'selected role set must provide command method' );
return;
};
done_testing;
( run in 1.634 second using v1.01-cache-2.11-cpan-ac8be02dad9 )