Assert-Refute
view release on metacpan or search on metacpan
lib/Assert/Refute/T/Basic.pm view on Meta::CPAN
package Assert::Refute::T::Basic;
use 5.006;
use strict;
use warnings;
our $VERSION = '0.1701';
=head1 NAME
Assert::Refute::T::Basic - a set of most common checks for Assert::Refute suite
=head1 DESCRIPTION
This module contains most common test conditions similar to those in
L<Test::More>, like C<is $got, $expected;> or C<like $got, qr/.../;>.
They appear as both exportable functions in this module
and L<Assert::Refute> itself
I<and> as corresponding methods in L<Assert::Refute::Report>.
=head1 FUNCTIONS
All functions below are prototyped to be used without parentheses and
exported by default. Scalar context is imposed onto arguments, so
is @foo, @bar;
would actually compare arrays by length.
If a C<contract { ... }> is in action, the results of each assertion
will be recorded there. See L<Assert::Refute::Report> for more.
If L<Test::More> is in action, a unit testing script is assumed.
If neither is true, an exception is thrown.
In addition, a C<Assert::Refute::Report-E<gt>function_name> method with
the same signature is generated for each of them
(see L<Assert::Refute::Build>).
=cut
use Carp;
use Scalar::Util qw(blessed looks_like_number refaddr);
use parent qw(Exporter);
use Assert::Refute::Build;
our @EXPORT = qw( diag note );
our @EXPORT_OK;
=head2 is $got, $expected, "explanation"
Check for equality, C<undef> equals C<undef> and nothing else.
=cut
build_refute is => sub {
my ($got, $exp) = @_;
if (defined $got xor defined $exp) {
return "unexpected ". to_scalar($got, 0);
};
return '' if !defined $got or $got eq $exp;
return sprintf "Got: %s\nExpected: %s"
, to_scalar($got, 0), to_scalar($exp, 0);
}, args => 2, export => 1;
=head2 isnt $got, $expected, "explanation"
The reverse of is().
=cut
build_refute isnt => sub {
my ($got, $exp) = @_;
return if defined $got xor defined $exp;
return "Unexpected: ".to_scalar($got)
if !defined $got or $got eq $exp;
}, args => 2, export => 1;
=head2 ok $condition, "explanation"
=cut
build_refute ok => sub {
my $got = shift;
return !$got;
}, args => 1, export => 1;
=head2 use_ok $module, [ @arguments ]
Check whether the module can be loaded correctly with given arguments.
This never dies, only returns a failure.
=cut
# TODO write it better
build_refute use_ok => sub {
my ($mod, @arg) = @_;
my $caller = caller(1);
eval "package $caller; use $mod \@arg; 1" and return ''; ## no critic
return "Failed to use $mod: ".($@ || "(unknown error)");
}, list => 1, export => 1;
=head1 require_ok My::Module
Require, but do not call import.
This never dies, only returns a failure.
=cut
build_refute require_ok => sub {
my ($mod, @arg) = @_;
my $caller = caller(1);
eval "package $caller; require $mod; 1" and return ''; ## no critic
return "Failed to require $mod: ".($@ || "(unknown error)");
}, args => 1, export => 1;
=head2 cpm_ok $value1, 'operation', $value2, "explanation"
Currently supported: C<E<lt> E<lt>= == != E<gt>= E<gt>>
C<lt le eq ne ge gt>
Fails if any argument is undefined.
=cut
my %compare;
$compare{$_} = eval "sub { return \$_[0] $_ \$_[1]; }" ## no critic
for qw( < <= == != >= > lt le eq ne ge gt );
my %numeric;
$numeric{$_}++ for qw( < <= == != >= > );
build_refute cmp_ok => sub {
my ($x, $op, $y) = @_;
my $fun = $compare{$op};
croak "cmp_ok(): Comparison '$op' not implemented"
unless $fun;
my @missing;
if ($numeric{$op}) {
push @missing, '1 '.to_scalar($x).' is not numeric'
unless looks_like_number $x or blessed $x;
push @missing, '2 '.to_scalar($y).' is not numeric'
unless looks_like_number $y or blessed $y;
} else {
push @missing, '1 is undefined' unless defined $x;
push @missing, '2 is undefined' unless defined $y;
};
return "cmp_ok '$op': argument ". join ", ", @missing
if @missing;
return '' if $fun->($x, $y);
return "$x\nis not '$op'\n$y";
}, args => 3, export => 1;
=head2 like $got, qr/.../, "explanation"
=head2 like $got, "regex", "explanation"
B<UNLIKE> L<Test::More>, accepts string argument just fine.
If argument is plain scalar, it is anchored to match the WHOLE string,
so that C<"foobar"> does NOT match C<"ob">,
but DOES match C<".*ob.*"> OR C<qr/ob/>.
=head2 unlike $got, "regex", "explanation"
The exact reverse of the above.
B<UNLIKE> L<Test::More>, accepts string argument just fine.
If argument is plain scalar, it is anchored to match the WHOLE string,
so that C<"foobar"> does NOT match C<"ob">,
but DOES match C<".*ob.*"> OR C<qr/ob/>.
=cut
build_refute like => \&_like_unlike,
args => 2, export => 1;
build_refute unlike => sub {
_like_unlike( $_[0], $_[1], 1 );
}, args => 2, export => 1;
sub _like_unlike {
my ($str, $reg, $reverse) = @_;
$reg = qr#^(?:$reg)$# unless ref $reg eq 'Regexp';
# retain compatibility with Test::More
return "got (undef), expecting ".($reverse ? "anything except" : "")."\n$reg"
if !defined $str;
return '' if $str =~ $reg xor $reverse;
return "$str\n".($reverse ? "unexpectedly matches" : "doesn't match")."\n$reg";
};
=head2 can_ok
=cut
build_refute can_ok => sub {
my $class = shift;
croak ("can_ok(): no methods to check!")
( run in 0.459 second using v1.01-cache-2.11-cpan-39bf76dae61 )