The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
=head1 PURPOSE

Test various scalars and roles to check we get expected results.

=head1 AUTHOR

Toby Inkster E<lt>tobyink@cpan.orgE<gt>.

=head1 COPYRIGHT AND LICENCE

This software is copyright (c) 2012-2013 by Toby Inkster.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut

use strict;
use warnings;
use Test::More;

use Scalar::Does;

{
	package Local::Does::Array;
	use overload '@{}' => 'array';
	sub new   { bless +{ array=>[] }, pop };
	sub array { return shift->{array} };
	sub DOES  { return 1 if $_[1] eq 'Monkey'; shift->SUPER::DOES(@_) }
}

{
	package Local::Does::Not;
	sub new   { bless +{ array=>[] }, pop };
	sub can   { return if $_[1] eq 'DOES'; shift->SUPER::can(@_) }
	sub DOES  { +die }
}

{
	package Cruddy::Role;
	sub new   { bless +{ array=>[] }, pop };
}

{
	package Permissive::Role;
	sub new   { bless +{ array=>[] }, pop };
	sub check { 1 }
}

my %tests = (
	undef => [
		undef,
		does   => [qw( 0+ "" bool )],
		doesnt => [qw( SCALAR @{} Regexp CODE &{} Foo::Bar UNIVERSAL )],
	],
	ARRAY => [
		[],
		does   => [qw( ARRAY @{} )],
		doesnt => [qw( HASH %{} )],
	],
	HASH => [
		+{},
		does   => [qw( HASH %{} )],
		doesnt => [qw( ARRAY @{} )],
	],
	SCALAR => [
		\"Hello World",
		does   => [qw( SCALAR ${} )],
		doesnt => [qw( ARRAY HASH @{} %{} CODE Regexp Foo::Bar UNIVERSAL )],
	],
	CODE => [
		sub { 1 },
		does   => [qw( CODE &{} )],
		doesnt => [qw( SCALAR @{} UNIVERSAL )],
	],
	Blessed_CODE => [
		bless(sub { 1 } => 'Foo::Bar'),
		does   => [qw( CODE &{} Foo::Bar UNIVERSAL )],
		doesnt => [qw( SCALAR @{} Regexp )],
	],
	Overloaded_Object => [
		Local::Does::Array->new,
		does   => [qw( ARRAY @{} HASH %{} Local::Does::Array UNIVERSAL Monkey )],
		doesnt => [qw( CODE bool "" Gorilla )],
	],
	Overloaded_Class => [
		'Local::Does::Array',
		does   => [qw( bool "" Local::Does::Array UNIVERSAL Monkey )],
		doesnt => [qw( CODE Gorilla HASH %{} ARRAY @{} )],
	],
	STDOUT => [
		\*STDOUT,
		does   => [qw( IO <> GLOB *{} )],
		doesnt => [qw( SCALAR @{} Regexp CODE &{} Foo::Bar UNIVERSAL )],
	],
	Lvalue => [
		\(substr($INC[0], 0, 1)),
		does   => [qw( LVALUE )],
		doesnt => [qw( SCALAR @{} Regexp CODE &{} Foo::Bar UNIVERSAL IO GLOB )],
	],
	Object_without_DOES_method => [
		Local::Does::Not->new,
		does   => [qw( HASH )],
		doesnt => [qw( Local::Does::Not )],
	],
	Class_without_DOES_method => [
		'Local::Does::Not',
		does   => [qw( )],
		doesnt => [qw( Local::Does::Not HASH )],
	],
);



my @uncheck = (
	Cruddy::Role->new,
	[],
	'FlibbleSocks',
);
my @check = (
	Permissive::Role->new,
);

foreach my $name (sort keys %tests)
{
	my ($value, %cases) = @{ $tests{$name} };
	
	foreach my $tc (@{ $cases{does} }) {
		ok(does($value, $tc), "$name does $tc");
	}

	foreach my $tc (@{ $cases{doesnt} }) {
		ok(!does($value, $tc), "$name doesn't $tc");
	}
	
	ok( does($value, $_), "$name does $_") for @check;
	ok(!does($value, $_), "$name doesn't do uncheckable role $_") for @uncheck;
}

done_testing();