Initial Commit
This commit is contained in:
176
database/perl/vendor/lib/Test2/Tools/AsyncSubtest.pm
vendored
Normal file
176
database/perl/vendor/lib/Test2/Tools/AsyncSubtest.pm
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
package Test2::Tools::AsyncSubtest;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Test2::IPC;
|
||||
use Test2::AsyncSubtest;
|
||||
use Test2::API qw/context/;
|
||||
use Carp qw/croak/;
|
||||
|
||||
our @EXPORT = qw/async_subtest fork_subtest thread_subtest/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub async_subtest {
|
||||
my $name = shift;
|
||||
my ($params, $code);
|
||||
$params = shift(@_) if @_ && ref($_[0]) eq 'HASH';
|
||||
$code = shift(@_) if @_ && ref($_[0]) eq 'CODE';
|
||||
|
||||
my $ctx = context();
|
||||
|
||||
my $subtest = Test2::AsyncSubtest->new(name => $name, context => 1, hub_init_args => $params);
|
||||
|
||||
$subtest->run($code, $subtest) if $code;
|
||||
|
||||
$ctx->release;
|
||||
return $subtest;
|
||||
}
|
||||
|
||||
sub fork_subtest {
|
||||
my $name = shift;
|
||||
my ($params, $code);
|
||||
$params = shift(@_) if @_ && ref($_[0]) eq 'HASH';
|
||||
$code = shift(@_) if @_ && ref($_[0]) eq 'CODE';
|
||||
|
||||
my $ctx = context();
|
||||
|
||||
croak "fork_subtest requires a CODE reference as the second argument"
|
||||
unless ref($code) eq 'CODE';
|
||||
|
||||
my $subtest = Test2::AsyncSubtest->new(name => $name, context => 1, hub_init_args => $params);
|
||||
|
||||
$subtest->run_fork($code, $subtest);
|
||||
|
||||
$ctx->release;
|
||||
return $subtest;
|
||||
}
|
||||
|
||||
sub thread_subtest {
|
||||
my $name = shift;
|
||||
my ($params, $code);
|
||||
$params = shift(@_) if @_ && ref($_[0]) eq 'HASH';
|
||||
$code = shift(@_) if @_ && ref($_[0]) eq 'CODE';
|
||||
|
||||
my $ctx = context();
|
||||
|
||||
croak "thread_subtest requires a CODE reference as the second argument"
|
||||
unless ref($code) eq 'CODE';
|
||||
|
||||
my $subtest = Test2::AsyncSubtest->new(name => $name, context => 1, hub_init_args => $params);
|
||||
|
||||
$subtest->run_thread($code, $subtest);
|
||||
|
||||
$ctx->release;
|
||||
return $subtest;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::AsyncSubtest - Tools for writing async subtests.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
These are tools for writing async subtests. Async subtests are subtests which
|
||||
can be started and stashed so that they can continue to receive events while
|
||||
other events are also being generated.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Bundle::Extended;
|
||||
use Test2::Tools::AsyncSubtest;
|
||||
|
||||
my $ast1 = async_subtest local => sub {
|
||||
ok(1, "Inside subtest");
|
||||
};
|
||||
|
||||
my $ast2 = fork_subtest child => sub {
|
||||
ok(1, "Inside subtest in another process");
|
||||
};
|
||||
|
||||
# You must call finish on the subtests you create. Finish will wait/join on
|
||||
# any child processes and threads.
|
||||
$ast1->finish;
|
||||
$ast2->finish;
|
||||
|
||||
done_testing;
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
Everything is exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item $ast = async_subtest $name
|
||||
|
||||
=item $ast = async_subtest $name => sub { ... }
|
||||
|
||||
=item $ast = async_subtest $name => \%hub_params, sub { ... }
|
||||
|
||||
Create an async subtest. Run the codeblock if it is provided.
|
||||
|
||||
=item $ast = fork_subtest $name => sub { ... }
|
||||
|
||||
=item $ast = fork_subtest $name => \%hub_params, sub { ... }
|
||||
|
||||
Create an async subtest. Run the codeblock in a forked process.
|
||||
|
||||
=item $ast = thread_subtest $name => sub { ... }
|
||||
|
||||
=item $ast = thread_subtest $name => \%hub_params, sub { ... }
|
||||
|
||||
B<** DISCOURAGED **> Threads are fragile. Thread tests are not even run unless
|
||||
the AUTHOR_TESTING or T2_DO_THREAD_TESTS env vars are enabled.
|
||||
|
||||
Create an async subtest. Run the codeblock in a thread.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
=over 4
|
||||
|
||||
=item Async Subtests are always buffered.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-AsyncSubtest can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist7@gmail.comE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
355
database/perl/vendor/lib/Test2/Tools/Basic.pm
vendored
Normal file
355
database/perl/vendor/lib/Test2/Tools/Basic.pm
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
package Test2::Tools::Basic;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Carp qw/croak/;
|
||||
use Test2::API qw/context/;
|
||||
|
||||
our @EXPORT = qw{
|
||||
ok pass fail diag note todo skip
|
||||
plan skip_all done_testing bail_out
|
||||
};
|
||||
use base 'Exporter';
|
||||
|
||||
sub ok($;$@) {
|
||||
my ($bool, $name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
$ctx->ok($bool, $name, \@diag);
|
||||
$ctx->release;
|
||||
return $bool ? 1 : 0;
|
||||
}
|
||||
|
||||
sub pass {
|
||||
my ($name) = @_;
|
||||
my $ctx = context();
|
||||
$ctx->ok(1, $name);
|
||||
$ctx->release;
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub fail {
|
||||
my ($name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
$ctx->ok(0, $name, \@diag);
|
||||
$ctx->release;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub diag {
|
||||
my $ctx = context();
|
||||
$ctx->diag( join '', grep { defined $_ } @_ );
|
||||
$ctx->release;
|
||||
}
|
||||
|
||||
sub note {
|
||||
my $ctx = context();
|
||||
$ctx->note( join '', grep { defined $_ } @_ );
|
||||
$ctx->release;
|
||||
}
|
||||
|
||||
sub todo {
|
||||
my $reason = shift;
|
||||
my $code = shift;
|
||||
|
||||
require Test2::Todo unless $INC{'Test2/Todo.pm'};
|
||||
my $todo = Test2::Todo->new(reason => $reason);
|
||||
|
||||
return $code->() if $code;
|
||||
|
||||
croak "Cannot use todo() in a void context without a codeblock"
|
||||
unless defined wantarray;
|
||||
|
||||
return $todo;
|
||||
}
|
||||
|
||||
sub skip {
|
||||
my ($why, $num) = @_;
|
||||
$num ||= 1;
|
||||
my $ctx = context();
|
||||
$ctx->skip("skipped test", $why) for 1 .. $num;
|
||||
$ctx->release;
|
||||
no warnings 'exiting';
|
||||
last SKIP;
|
||||
}
|
||||
|
||||
sub plan {
|
||||
my $plan = shift;
|
||||
my $ctx = context();
|
||||
|
||||
if ($plan && $plan =~ m/[^0-9]/) {
|
||||
if ($plan eq 'tests') {
|
||||
$plan = shift;
|
||||
}
|
||||
elsif ($plan eq 'skip_all') {
|
||||
skip_all(@_);
|
||||
$ctx->release;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$ctx->plan($plan);
|
||||
$ctx->release;
|
||||
}
|
||||
|
||||
sub skip_all {
|
||||
my ($reason) = @_;
|
||||
my $ctx = context();
|
||||
$ctx->plan(0, SKIP => $reason);
|
||||
$ctx->release if $ctx;
|
||||
}
|
||||
|
||||
sub done_testing {
|
||||
my $ctx = context();
|
||||
$ctx->hub->finalize($ctx->trace, 1);
|
||||
$ctx->release;
|
||||
}
|
||||
|
||||
sub bail_out {
|
||||
my ($reason) = @_;
|
||||
my $ctx = context();
|
||||
$ctx->bail($reason);
|
||||
$ctx->release if $ctx;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Basic - Test2 implementation of the basic testing tools.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a L<Test2> based implementation of the more basic tools originally
|
||||
provided by L<Test::More>. Not all L<Test::More> tools are provided by this
|
||||
package, only the basic/simple ones. Some tools have been modified for better
|
||||
diagnostics capabilities.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Basic;
|
||||
|
||||
ok($x, "simple test");
|
||||
|
||||
if ($passing) {
|
||||
pass('a passing test');
|
||||
}
|
||||
else {
|
||||
fail('a failing test');
|
||||
}
|
||||
|
||||
diag "This is a diagnostics message on STDERR";
|
||||
note "This is a diagnostics message on STDOUT";
|
||||
|
||||
{
|
||||
my $todo = todo "Reason for todo";
|
||||
ok(0, "this test is todo");
|
||||
}
|
||||
|
||||
ok(1, "this test is not todo");
|
||||
|
||||
todo "reason" => sub {
|
||||
ok(0, "this test is todo");
|
||||
};
|
||||
|
||||
ok(1, "this test is not todo");
|
||||
|
||||
SKIP: {
|
||||
skip "This will wipe your drive";
|
||||
|
||||
# This never gets run:
|
||||
ok(!system('sudo rm -rf /'), "Wipe drive");
|
||||
}
|
||||
|
||||
done_testing;
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All subs are exported by default.
|
||||
|
||||
=head2 PLANNING
|
||||
|
||||
=over 4
|
||||
|
||||
=item plan($num)
|
||||
|
||||
=item plan('tests' => $num)
|
||||
|
||||
=item plan('skip_all' => $reason)
|
||||
|
||||
Set the number of tests that are expected. This must be done first or last,
|
||||
never in the middle of testing.
|
||||
|
||||
For legacy compatibility you can specify 'tests' as the first argument before
|
||||
the number. You can also use this to skip all with the 'skip_all' prefix,
|
||||
followed by a reason for skipping.
|
||||
|
||||
=item skip_all($reason)
|
||||
|
||||
Set the plan to 0 with a reason, then exit true. This should be used before any
|
||||
tests are run.
|
||||
|
||||
=item done_testing
|
||||
|
||||
Used to mark the end of testing. This is a safe way to have a dynamic or
|
||||
unknown number of tests.
|
||||
|
||||
=item bail_out($reason)
|
||||
|
||||
Invoked when something has gone horribly wrong: stop everything, kill all threads and
|
||||
processes, end the process with a false exit status.
|
||||
|
||||
=back
|
||||
|
||||
=head2 ASSERTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item ok($bool)
|
||||
|
||||
=item ok($bool, $name)
|
||||
|
||||
=item ok($bool, $name, @diag)
|
||||
|
||||
Simple assertion. If C<$bool> is true the test passes, and if it is false the test
|
||||
fails. The test name is optional, and all arguments after the name are added as
|
||||
diagnostics message if and only if the test fails. If the test passes all the
|
||||
diagnostics arguments will be ignored.
|
||||
|
||||
=item pass()
|
||||
|
||||
=item pass($name)
|
||||
|
||||
Fire off a passing test (a single Ok event). The name is optional
|
||||
|
||||
=item fail()
|
||||
|
||||
=item fail($name)
|
||||
|
||||
=item fail($name, @diag)
|
||||
|
||||
Fire off a failing test (a single Ok event). The name and diagnostics are optional.
|
||||
|
||||
=back
|
||||
|
||||
=head2 DIAGNOSTICS
|
||||
|
||||
=over 4
|
||||
|
||||
=item diag(@messages)
|
||||
|
||||
Write diagnostics messages. All items in C<@messages> will be joined into a
|
||||
single string with no separator. When using TAP, diagnostics are sent to STDERR.
|
||||
|
||||
=item note(@messages)
|
||||
|
||||
Write note-diagnostics messages. All items in C<@messages> will be joined into
|
||||
a single string with no separator. When using TAP, notes are sent to STDOUT.
|
||||
|
||||
=back
|
||||
|
||||
=head2 META
|
||||
|
||||
=over 4
|
||||
|
||||
=item $todo = todo($reason)
|
||||
|
||||
=item todo $reason => sub { ... }
|
||||
|
||||
This is used to mark some results as TODO. TODO means that the test may fail,
|
||||
but will not cause the overall test suite to fail.
|
||||
|
||||
There are two ways to use this. The first is to use a codeblock, and the TODO will
|
||||
only apply to the codeblock.
|
||||
|
||||
ok(1, "before"); # Not TODO
|
||||
|
||||
todo 'this will fail' => sub {
|
||||
# This is TODO, as is any other test in this block.
|
||||
ok(0, "blah");
|
||||
};
|
||||
|
||||
ok(1, "after"); # Not TODO
|
||||
|
||||
The other way is to use a scoped variable. TODO will end when the variable is
|
||||
destroyed or set to undef.
|
||||
|
||||
ok(1, "before"); # Not TODO
|
||||
|
||||
{
|
||||
my $todo = todo 'this will fail';
|
||||
|
||||
# This is TODO, as is any other test in this block.
|
||||
ok(0, "blah");
|
||||
};
|
||||
|
||||
ok(1, "after"); # Not TODO
|
||||
|
||||
This is the same thing, but without the C<{...}> scope.
|
||||
|
||||
ok(1, "before"); # Not TODO
|
||||
|
||||
my $todo = todo 'this will fail';
|
||||
|
||||
ok(0, "blah"); # TODO
|
||||
|
||||
$todo = undef;
|
||||
|
||||
ok(1, "after"); # Not TODO
|
||||
|
||||
=item skip($why)
|
||||
|
||||
=item skip($why, $count)
|
||||
|
||||
This is used to skip some tests. This requires you to wrap your tests in a
|
||||
block labeled C<SKIP:>. This is somewhat magical. If no C<$count> is specified
|
||||
then it will issue a single result. If you specify C<$count> it will issue that
|
||||
many results.
|
||||
|
||||
SKIP: {
|
||||
skip "This will wipe your drive";
|
||||
|
||||
# This never gets run:
|
||||
ok(!system('sudo rm -rf /'), "Wipe drive");
|
||||
}
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
193
database/perl/vendor/lib/Test2/Tools/Class.pm
vendored
Normal file
193
database/perl/vendor/lib/Test2/Tools/Class.pm
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
package Test2::Tools::Class;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Test2::API qw/context/;
|
||||
use Test2::Util::Ref qw/render_ref/;
|
||||
|
||||
use Scalar::Util qw/blessed/;
|
||||
|
||||
our @EXPORT = qw/can_ok isa_ok DOES_ok/;
|
||||
use base 'Exporter';
|
||||
|
||||
# For easier grepping
|
||||
# sub isa_ok is defined here
|
||||
# sub can_ok is defined here
|
||||
# sub DOES_ok is defined here
|
||||
BEGIN {
|
||||
for my $op (qw/isa can DOES/) {
|
||||
my $sub = sub($;@) {
|
||||
my ($thing, @args) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
my (@items, $name);
|
||||
if (ref($args[0]) eq 'ARRAY') {
|
||||
$name = $args[1];
|
||||
@items = @{$args[0]};
|
||||
}
|
||||
else {
|
||||
@items = @args;
|
||||
}
|
||||
|
||||
my $thing_name = ref($thing) ? render_ref($thing) : defined($thing) ? "$thing" : "<undef>";
|
||||
$thing_name =~ s/\n/\\n/g;
|
||||
$thing_name =~ s/#//g;
|
||||
$thing_name =~ s/\(0x[a-f0-9]+\)//gi;
|
||||
|
||||
$name ||= @items == 1 ? "$thing_name\->$op('$items[0]')" : "$thing_name\->$op(...)";
|
||||
|
||||
unless (defined($thing) && (blessed($thing) || !ref($thing) && length($thing))) {
|
||||
my $thing = defined($thing)
|
||||
? ref($thing) || "'$thing'"
|
||||
: '<undef>';
|
||||
|
||||
$ctx->ok(0, $name, ["$thing is neither a blessed reference or a package name."]);
|
||||
|
||||
$ctx->release;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unless(UNIVERSAL->can($op) || $thing->can($op)) {
|
||||
$ctx->skip($name, "'$op' is not supported on this platform");
|
||||
$ctx->release;
|
||||
return 1;
|
||||
}
|
||||
|
||||
my $file = $ctx->trace->file;
|
||||
my $line = $ctx->trace->line;
|
||||
|
||||
my @bad;
|
||||
for my $item (@items) {
|
||||
my ($bool, $ok, $err);
|
||||
|
||||
{
|
||||
local ($@, $!);
|
||||
$ok = eval qq/#line $line "$file"\n\$bool = \$thing->$op(\$item); 1/;
|
||||
$err = $@;
|
||||
}
|
||||
|
||||
die $err unless $ok;
|
||||
next if $bool;
|
||||
|
||||
push @bad => $item;
|
||||
}
|
||||
|
||||
$ctx->ok( !@bad, $name, [map { "Failed: $thing_name\->$op('$_')" } @bad]);
|
||||
|
||||
$ctx->release;
|
||||
|
||||
return !@bad;
|
||||
};
|
||||
|
||||
no strict 'refs';
|
||||
*{$op . "_ok"} = $sub;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Class - Test2 implementation of the tools for testing classes.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Test2> based tools for validating classes and objects. These are similar to
|
||||
some tools from L<Test::More>, but they have a more consistent interface.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Class;
|
||||
|
||||
isa_ok($CLASS_OR_INSTANCE, $PARENT_CLASS1, $PARENT_CLASS2, ...);
|
||||
isa_ok($CLASS_OR_INSTANCE, [$PARENT_CLASS1, $PARENT_CLASS2, ...], "Test Name");
|
||||
|
||||
can_ok($CLASS_OR_INSTANCE, $METHOD1, $METHOD2, ...);
|
||||
can_ok($CLASS_OR_INSTANCE, [$METHOD1, $METHOD2, ...], "Test Name");
|
||||
|
||||
DOES_ok($CLASS_OR_INSTANCE, $ROLE1, $ROLE2, ...);
|
||||
DOES_ok($CLASS_OR_INSTANCE, [$ROLE1, $ROLE2, ...], "Test Name");
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All subs are exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item can_ok($thing, @methods)
|
||||
|
||||
=item can_ok($thing, \@methods, $test_name)
|
||||
|
||||
This checks that C<$thing> (either a class name, or a blessed instance) has the
|
||||
specified methods.
|
||||
|
||||
If the second argument is an arrayref then it will be used as the list of
|
||||
methods leaving the third argument to be the test name.
|
||||
|
||||
=item isa_ok($thing, @classes)
|
||||
|
||||
=item isa_ok($thing, \@classes, $test_name)
|
||||
|
||||
This checks that C<$thing> (either a class name, or a blessed instance) is or
|
||||
subclasses the specified classes.
|
||||
|
||||
If the second argument is an arrayref then it will be used as the list of
|
||||
classes leaving the third argument to be the test name.
|
||||
|
||||
=item DOES_ok($thing, @roles)
|
||||
|
||||
=item DOES_ok($thing, \@roles, $test_name)
|
||||
|
||||
This checks that C<$thing> (either a class name, or a blessed instance) does
|
||||
the specified roles.
|
||||
|
||||
If the second argument is an arrayref then it will be used as the list of
|
||||
roles leaving the third argument to be the test name.
|
||||
|
||||
B<Note 1:> This uses the C<< $class->DOES(...) >> method, not the C<does()>
|
||||
method Moose provides.
|
||||
|
||||
B<Note 2:> Not all perls have the C<DOES()> method, if you use this on those
|
||||
perls the test will be skipped.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
514
database/perl/vendor/lib/Test2/Tools/ClassicCompare.pm
vendored
Normal file
514
database/perl/vendor/lib/Test2/Tools/ClassicCompare.pm
vendored
Normal file
@@ -0,0 +1,514 @@
|
||||
package Test2::Tools::ClassicCompare;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
our @EXPORT = qw/is is_deeply isnt like unlike cmp_ok/;
|
||||
use base 'Exporter';
|
||||
|
||||
use Carp qw/carp/;
|
||||
use Scalar::Util qw/reftype/;
|
||||
|
||||
use Test2::API qw/context/;
|
||||
use Test2::Compare qw/compare strict_convert/;
|
||||
use Test2::Util::Ref qw/rtype render_ref/;
|
||||
use Test2::Util::Table qw/table/;
|
||||
|
||||
use Test2::Compare::Array();
|
||||
use Test2::Compare::Bag();
|
||||
use Test2::Compare::Custom();
|
||||
use Test2::Compare::Event();
|
||||
use Test2::Compare::Hash();
|
||||
use Test2::Compare::Meta();
|
||||
use Test2::Compare::Number();
|
||||
use Test2::Compare::Object();
|
||||
use Test2::Compare::OrderedSubset();
|
||||
use Test2::Compare::Pattern();
|
||||
use Test2::Compare::Ref();
|
||||
use Test2::Compare::Regex();
|
||||
use Test2::Compare::Scalar();
|
||||
use Test2::Compare::Set();
|
||||
use Test2::Compare::String();
|
||||
use Test2::Compare::Undef();
|
||||
use Test2::Compare::Wildcard();
|
||||
|
||||
sub is($$;$@) {
|
||||
my ($got, $exp, $name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
my @caller = caller;
|
||||
|
||||
my $delta = compare($got, $exp, \&is_convert);
|
||||
|
||||
if ($delta) {
|
||||
$ctx->fail($name, $delta->diag, @diag);
|
||||
}
|
||||
else {
|
||||
$ctx->ok(1, $name);
|
||||
}
|
||||
|
||||
$ctx->release;
|
||||
return !$delta;
|
||||
}
|
||||
|
||||
sub isnt($$;$@) {
|
||||
my ($got, $exp, $name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
my @caller = caller;
|
||||
|
||||
my $delta = compare($got, $exp, \&isnt_convert);
|
||||
|
||||
if ($delta) {
|
||||
$ctx->fail($name, $delta->diag, @diag);
|
||||
}
|
||||
else {
|
||||
$ctx->ok(1, $name);
|
||||
}
|
||||
|
||||
$ctx->release;
|
||||
return !$delta;
|
||||
}
|
||||
|
||||
sub is_convert {
|
||||
my ($thing) = @_;
|
||||
return Test2::Compare::Undef->new()
|
||||
unless defined $thing;
|
||||
return Test2::Compare::String->new(input => $thing);
|
||||
}
|
||||
|
||||
sub isnt_convert {
|
||||
my ($thing) = @_;
|
||||
return Test2::Compare::Undef->new()
|
||||
unless defined $thing;
|
||||
my $str = Test2::Compare::String->new(input => $thing, negate => 1);
|
||||
}
|
||||
|
||||
sub like($$;$@) {
|
||||
my ($got, $exp, $name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
my $delta = compare($got, $exp, \&like_convert);
|
||||
|
||||
if ($delta) {
|
||||
$ctx->fail($name, $delta->diag, @diag);
|
||||
}
|
||||
else {
|
||||
$ctx->ok(1, $name);
|
||||
}
|
||||
|
||||
$ctx->release;
|
||||
return !$delta;
|
||||
}
|
||||
|
||||
sub unlike($$;$@) {
|
||||
my ($got, $exp, $name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
my $delta = compare($got, $exp, \&unlike_convert);
|
||||
|
||||
if ($delta) {
|
||||
$ctx->fail($name, $delta->diag, @diag);
|
||||
}
|
||||
else {
|
||||
$ctx->ok(1, $name);
|
||||
}
|
||||
|
||||
$ctx->release;
|
||||
return !$delta;
|
||||
}
|
||||
|
||||
sub like_convert {
|
||||
my ($thing) = @_;
|
||||
return Test2::Compare::Pattern->new(
|
||||
pattern => $thing,
|
||||
stringify_got => 1,
|
||||
);
|
||||
}
|
||||
|
||||
sub unlike_convert {
|
||||
my ($thing) = @_;
|
||||
return Test2::Compare::Pattern->new(
|
||||
negate => 1,
|
||||
stringify_got => 1,
|
||||
pattern => $thing,
|
||||
);
|
||||
}
|
||||
|
||||
sub is_deeply($$;$@) {
|
||||
my ($got, $exp, $name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
my @caller = caller;
|
||||
|
||||
my $delta = compare($got, $exp, \&strict_convert);
|
||||
|
||||
if ($delta) {
|
||||
# Temporary thing.
|
||||
my $count = 0;
|
||||
my $implicit = 0;
|
||||
my @deltas = ($delta);
|
||||
while (my $d = shift @deltas) {
|
||||
my $add = $d->children;
|
||||
push @deltas => @$add if $add && @$add;
|
||||
next if $d->verified;
|
||||
$count++;
|
||||
$implicit++ if $d->note && $d->note eq 'implicit end';
|
||||
}
|
||||
|
||||
if ($implicit == $count) {
|
||||
$ctx->ok(1, $name);
|
||||
my $meth = $ENV{AUTHOR_TESTING} ? 'throw' : 'alert';
|
||||
my $type = $delta->render_check;
|
||||
$ctx->$meth(
|
||||
join "\n",
|
||||
"!!! NOTICE OF BEHAVIOR CHANGE !!!",
|
||||
"This test uses at least 1 $type check without using end() or etc().",
|
||||
"The exising behavior is to default to etc() when inside is_deeply().",
|
||||
"The new behavior is to default to end().",
|
||||
"This test will soon start to fail with the following diagnostics:",
|
||||
$delta->diag,
|
||||
"",
|
||||
);
|
||||
}
|
||||
else {
|
||||
$ctx->fail($name, $delta->diag, @diag);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$ctx->ok(1, $name);
|
||||
}
|
||||
|
||||
$ctx->release;
|
||||
return !$delta;
|
||||
}
|
||||
|
||||
our %OPS = (
|
||||
'==' => 'num',
|
||||
'!=' => 'num',
|
||||
'>=' => 'num',
|
||||
'<=' => 'num',
|
||||
'>' => 'num',
|
||||
'<' => 'num',
|
||||
'<=>' => 'num',
|
||||
|
||||
'eq' => 'str',
|
||||
'ne' => 'str',
|
||||
'gt' => 'str',
|
||||
'lt' => 'str',
|
||||
'ge' => 'str',
|
||||
'le' => 'str',
|
||||
'cmp' => 'str',
|
||||
'!~' => 'str',
|
||||
'=~' => 'str',
|
||||
|
||||
'&&' => 'logic',
|
||||
'||' => 'logic',
|
||||
'xor' => 'logic',
|
||||
'or' => 'logic',
|
||||
'and' => 'logic',
|
||||
'//' => 'logic',
|
||||
|
||||
'&' => 'bitwise',
|
||||
'|' => 'bitwise',
|
||||
|
||||
'~~' => 'match',
|
||||
);
|
||||
sub cmp_ok($$$;$@) {
|
||||
my ($got, $op, $exp, $name, @diag) = @_;
|
||||
|
||||
my $ctx = context();
|
||||
|
||||
# Warnings and syntax errors should report to the cmp_ok call, not the test
|
||||
# context. They may not be the same.
|
||||
my ($pkg, $file, $line) = caller;
|
||||
|
||||
my $type = $OPS{$op};
|
||||
if (!$type) {
|
||||
carp "operator '$op' is not supported (you can add it to %Test2::Tools::ClassicCompare::OPS)";
|
||||
$type = 'unsupported';
|
||||
}
|
||||
|
||||
local ($@, $!, $SIG{__DIE__});
|
||||
|
||||
my $test;
|
||||
my $lived = eval <<" EOT";
|
||||
#line $line "(eval in cmp_ok) $file"
|
||||
\$test = (\$got $op \$exp);
|
||||
1;
|
||||
EOT
|
||||
my $error = $@;
|
||||
$ctx->send_event('Exception', error => $error) unless $lived;
|
||||
|
||||
if ($test && $lived) {
|
||||
$ctx->ok(1, $name);
|
||||
$ctx->release;
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Ugh, it failed. Do roughly the same thing Test::More did to try and show
|
||||
# diagnostics, but make it better by showing both the overloaded and
|
||||
# unoverloaded form if overloading is in play. Also unoverload numbers,
|
||||
# Test::More only unoverloaded strings.
|
||||
|
||||
my ($display_got, $display_exp);
|
||||
if($type eq 'str') {
|
||||
$display_got = defined($got) ? "$got" : undef;
|
||||
$display_exp = defined($exp) ? "$exp" : undef;
|
||||
}
|
||||
elsif($type eq 'num') {
|
||||
$display_got = defined($got) ? $got + 0 : undef;
|
||||
$display_exp = defined($exp) ? $exp + 0 : undef;
|
||||
}
|
||||
else { # Well, we did what we could.
|
||||
$display_got = $got;
|
||||
$display_exp = $exp;
|
||||
}
|
||||
|
||||
my $got_ref = ref($got) ? render_ref($got) : $got;
|
||||
my $exp_ref = ref($exp) ? render_ref($exp) : $exp;
|
||||
|
||||
my @table;
|
||||
my $show_both = (
|
||||
(defined($got) && $got_ref ne "$display_got")
|
||||
||
|
||||
(defined($exp) && $exp_ref ne "$display_exp")
|
||||
);
|
||||
|
||||
if ($show_both) {
|
||||
@table = table(
|
||||
header => ['TYPE', 'GOT', 'OP', 'CHECK'],
|
||||
rows => [
|
||||
[$type, $display_got, $op, $lived ? $display_exp : '<EXCEPTION>'],
|
||||
['orig', $got_ref, '', $exp_ref],
|
||||
],
|
||||
);
|
||||
}
|
||||
else {
|
||||
@table = table(
|
||||
header => ['GOT', 'OP', 'CHECK'],
|
||||
rows => [[$display_got, $op, $lived ? $display_exp : '<EXCEPTION>']],
|
||||
);
|
||||
}
|
||||
|
||||
$ctx->ok(0, $name, [join("\n", @table), @diag]);
|
||||
$ctx->release;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::ClassicCompare - Classic (Test::More style) comparison tools.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This provides comparison functions that behave like they did in L<Test::More>,
|
||||
unlike the L<Test2::Tools::Compare> plugin which has modified them.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::ClassicCompare qw/is is_deeply isnt like unlike cmp_ok/;
|
||||
|
||||
is($got, $expect, "These are the same when stringified");
|
||||
isnt($got, $unexpect, "These are not the same when stringified");
|
||||
|
||||
like($got, qr/.../, "'got' matches the pattern");
|
||||
unlike($got, qr/.../, "'got' does not match the pattern");
|
||||
|
||||
is_deeply($got, $expect, "These structures are same when checked deeply");
|
||||
|
||||
cmp_ok($GOT, $OP, $WANT, 'Compare these items using the specified operatr');
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $bool = is($got, $expect)
|
||||
|
||||
=item $bool = is($got, $expect, $name)
|
||||
|
||||
=item $bool = is($got, $expect, $name, @diag)
|
||||
|
||||
This does a string comparison of the two arguments. If the two arguments are the
|
||||
same after stringification the test passes. The test will also pass if both
|
||||
arguments are undef.
|
||||
|
||||
The test C<$name> is optional.
|
||||
|
||||
The test C<@diag> is optional, it is extra diagnostics messages that will be
|
||||
displayed if the test fails. The diagnostics are ignored if the test passes.
|
||||
|
||||
It is important to note that this tool considers C<"1"> and C<"1.0"> to not be
|
||||
equal as it uses a string comparison.
|
||||
|
||||
See L<Test2::Tools::Compare> if you want an C<is()> function that tries
|
||||
to be smarter for you.
|
||||
|
||||
=item $bool = isnt($got, $dont_expect)
|
||||
|
||||
=item $bool = isnt($got, $dont_expect, $name)
|
||||
|
||||
=item $bool = isnt($got, $dont_expect, $name, @diag)
|
||||
|
||||
This is the inverse of C<is()>, it passes when the strings are not the same.
|
||||
|
||||
=item $bool = like($got, $pattern)
|
||||
|
||||
=item $bool = like($got, $pattern, $name)
|
||||
|
||||
=item $bool = like($got, $pattern, $name, @diag)
|
||||
|
||||
Check if C<$got> matches the specified pattern. Will fail if it does not match.
|
||||
|
||||
The test C<$name> is optional.
|
||||
|
||||
The test C<@diag> is optional. It contains extra diagnostics messages that will
|
||||
be displayed if the test fails. The diagnostics are ignored if the test passes.
|
||||
|
||||
=item $bool = unlike($got, $pattern)
|
||||
|
||||
=item $bool = unlike($got, $pattern, $name)
|
||||
|
||||
=item $bool = unlike($got, $pattern, $name, @diag)
|
||||
|
||||
This is the inverse of C<like()>. This will fail if C<$got> matches
|
||||
C<$pattern>.
|
||||
|
||||
=item $bool = is_deeply($got, $expect)
|
||||
|
||||
=item $bool = is_deeply($got, $expect, $name)
|
||||
|
||||
=item $bool = is_deeply($got, $expect, $name, @diag)
|
||||
|
||||
This does a deep check, comparing the structures in C<$got> with those in
|
||||
C<$expect>. It will recurse into hashrefs, arrayrefs, and scalar refs. All
|
||||
other values will be stringified and compared as strings. It is important to
|
||||
note that this tool considers C<"1"> and C<"1.0"> to not be equal as it uses a
|
||||
string comparison.
|
||||
|
||||
This is the same as C<Test2::Tools::Compare::is()>.
|
||||
|
||||
=item cmp_ok($got, $op, $expect)
|
||||
|
||||
=item cmp_ok($got, $op, $expect, $name)
|
||||
|
||||
=item cmp_ok($got, $op, $expect, $name, @diag)
|
||||
|
||||
Compare C<$got> to C<$expect> using the operator specified in C<$op>. This is
|
||||
effectively an C<eval "\$got $op \$expect"> with some other stuff to make it
|
||||
more sane. This is useful for comparing numbers, overloaded objects, etc.
|
||||
|
||||
B<Overloading Note:> Your input is passed as-is to the comparison.
|
||||
If the comparison fails between two overloaded objects, the diagnostics will
|
||||
try to show you the overload form that was used in comparisons. It is possible
|
||||
that the diagnostics will be wrong, though attempts have been made to improve
|
||||
them since L<Test::More>.
|
||||
|
||||
B<Exceptions:> If the comparison results in an exception then the test will
|
||||
fail and the exception will be shown.
|
||||
|
||||
C<cmp_ok()> has an internal list of operators it supports. If you provide an
|
||||
unsupported operator it will issue a warning. You can add operators to the
|
||||
C<%Test2::Tools::ClassicCompare::OPS> hash, the key should be the operator, and
|
||||
the value should either be 'str' for string comparison operators, 'num' for
|
||||
numeric operators, or any other true value for other operators.
|
||||
|
||||
Supported operators:
|
||||
|
||||
=over 4
|
||||
|
||||
=item == (num)
|
||||
|
||||
=item != (num)
|
||||
|
||||
=item >= (num)
|
||||
|
||||
=item <= (num)
|
||||
|
||||
=item > (num)
|
||||
|
||||
=item < (num)
|
||||
|
||||
=item <=> (num)
|
||||
|
||||
=item eq (str)
|
||||
|
||||
=item ne (str)
|
||||
|
||||
=item gt (str)
|
||||
|
||||
=item lt (str)
|
||||
|
||||
=item ge (str)
|
||||
|
||||
=item le (str)
|
||||
|
||||
=item cmp (str)
|
||||
|
||||
=item !~ (str)
|
||||
|
||||
=item =~ (str)
|
||||
|
||||
=item &&
|
||||
|
||||
=item ||
|
||||
|
||||
=item xor
|
||||
|
||||
=item or
|
||||
|
||||
=item and
|
||||
|
||||
=item //
|
||||
|
||||
=item &
|
||||
|
||||
=item |
|
||||
|
||||
=item ~~
|
||||
|
||||
=back
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
1793
database/perl/vendor/lib/Test2/Tools/Compare.pm
vendored
Normal file
1793
database/perl/vendor/lib/Test2/Tools/Compare.pm
vendored
Normal file
File diff suppressed because it is too large
Load Diff
173
database/perl/vendor/lib/Test2/Tools/Defer.pm
vendored
Normal file
173
database/perl/vendor/lib/Test2/Tools/Defer.pm
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package Test2::Tools::Defer;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Carp qw/croak/;
|
||||
|
||||
use Test2::Util qw/get_tid/;
|
||||
use Test2::API qw{
|
||||
test2_add_callback_exit
|
||||
test2_pid test2_tid
|
||||
};
|
||||
|
||||
our @EXPORT = qw/def do_def/;
|
||||
use base 'Exporter';
|
||||
|
||||
my %TODO;
|
||||
|
||||
sub def {
|
||||
my ($func, @args) = @_;
|
||||
|
||||
my @caller = caller(0);
|
||||
|
||||
$TODO{$caller[0]} ||= [];
|
||||
push @{$TODO{$caller[0]}} => [$func, \@args, \@caller];
|
||||
}
|
||||
|
||||
sub do_def {
|
||||
my $for = caller;
|
||||
my $tests = delete $TODO{$for} or croak "No tests to run!";
|
||||
|
||||
for my $test (@$tests) {
|
||||
my ($func, $args, $caller) = @$test;
|
||||
|
||||
my ($pkg, $file, $line) = @$caller;
|
||||
|
||||
chomp(my $eval = <<" EOT");
|
||||
package $pkg;
|
||||
# line $line "(eval in Test2::Tools::Defer) $file"
|
||||
\&$func(\@\$args);
|
||||
1;
|
||||
EOT
|
||||
|
||||
eval $eval and next;
|
||||
chomp(my $error = $@);
|
||||
|
||||
require Data::Dumper;
|
||||
chomp(my $td = Data::Dumper::Dumper($args));
|
||||
$td =~ s/^\$VAR1 =/\$args: /;
|
||||
die <<" EOT";
|
||||
Exception: $error
|
||||
--eval--
|
||||
$eval
|
||||
--------
|
||||
Tool: $func
|
||||
Caller: $caller->[0], $caller->[1], $caller->[2]
|
||||
$td
|
||||
EOT
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub _verify {
|
||||
my ($context, $exit, $new_exit) = @_;
|
||||
|
||||
my $not_ok = 0;
|
||||
for my $pkg (keys %TODO) {
|
||||
my $tests = delete $TODO{$pkg};
|
||||
my $caller = $tests->[0]->[-1];
|
||||
print STDOUT "not ok - deferred tests were not run!\n" unless $not_ok++;
|
||||
print STDERR "# '$pkg' has deferred tests that were never run!\n";
|
||||
print STDERR "# $caller->[1] at line $caller->[2]\n";
|
||||
$$new_exit ||= 255;
|
||||
}
|
||||
}
|
||||
|
||||
test2_add_callback_exit(\&_verify);
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Defer - Write tests that get executed at a later time
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Sometimes you need to test things BEFORE loading the necessary functions. This
|
||||
module lets you do that. You can write tests, and then have them run later,
|
||||
after C<Test2> is loaded. You tell it what test function to run, and what
|
||||
arguments to give it. The function name and arguments will be stored to be
|
||||
executed later. When ready, run C<do_def()> to kick them off once the functions
|
||||
are defined.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Test2::Tools::Defer;
|
||||
|
||||
BEGIN {
|
||||
def ok => (1, 'pass');
|
||||
def is => ('foo', 'foo', 'runs is');
|
||||
...
|
||||
}
|
||||
|
||||
use Test2::Tools::Basic;
|
||||
|
||||
do_def(); # Run the tests
|
||||
|
||||
# Declare some more tests to run later:
|
||||
def ok => (1, "another pass");
|
||||
...
|
||||
|
||||
do_def(); # run the new tests
|
||||
|
||||
done_testing;
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item def function => @args;
|
||||
|
||||
This will store the function name, and the arguments to be run later. Note that
|
||||
each package has a separate store of tests to run.
|
||||
|
||||
=item do_def()
|
||||
|
||||
This will run all the stored tests. It will also reset the list to be empty so
|
||||
you can add more tests to run even later.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
94
database/perl/vendor/lib/Test2/Tools/Encoding.pm
vendored
Normal file
94
database/perl/vendor/lib/Test2/Tools/Encoding.pm
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package Test2::Tools::Encoding;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Carp qw/croak/;
|
||||
|
||||
use Test2::API qw/test2_stack/;
|
||||
|
||||
use base 'Exporter';
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
our @EXPORT = qw/set_encoding/;
|
||||
|
||||
sub set_encoding {
|
||||
my $enc = shift;
|
||||
my $format = test2_stack->top->format;
|
||||
|
||||
unless ($format && eval { $format->can('encoding') }) {
|
||||
$format = '<undef>' unless defined $format;
|
||||
croak "Unable to set encoding on formatter '$format'";
|
||||
}
|
||||
|
||||
$format->encoding($enc);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Encoding - Tools for managing the encoding of L<Test2> based
|
||||
tests.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module exports a function that lets you dynamically change the output
|
||||
encoding at will.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Encoding;
|
||||
|
||||
set_encoding('utf8');
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All subs are exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item set_encoding($encoding)
|
||||
|
||||
This will set the encoding to whatever you specify. This will only affect the
|
||||
output of the current formatter, which is usually your TAP output formatter.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
95
database/perl/vendor/lib/Test2/Tools/Event.pm
vendored
Normal file
95
database/perl/vendor/lib/Test2/Tools/Event.pm
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package Test2::Tools::Event;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Test2::Util qw/pkg_to_file/;
|
||||
|
||||
our @EXPORT = qw/gen_event/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub gen_event {
|
||||
my ($type, %fields) = @_;
|
||||
|
||||
$type = "Test2::Event::$type" unless $type =~ s/^\+//;
|
||||
|
||||
require(pkg_to_file($type));
|
||||
|
||||
$fields{trace} ||= Test2::Util::Trace->new(frame => [caller(0)]);
|
||||
|
||||
return $type->new(%fields);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Event - Tools for generating test events.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module provides tools for generating events quickly by bypassing the
|
||||
context/hub. This is particularly useful when testing other L<Test2> packages.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $e = gen_event($TYPE)
|
||||
|
||||
=item $e = gen_event($TYPE, %FIELDS)
|
||||
|
||||
=item $e = gen_event 'Ok';
|
||||
|
||||
=item $e = gen_event Ok => ( ... )
|
||||
|
||||
=item $e = gen_event '+Test2::Event::Ok' => ( ... )
|
||||
|
||||
This will produce an event of the specified type. C<$TYPE> is assumed to be
|
||||
shorthand for C<Test2::Event::$TYPE>, you can prefix C<$TYPE> with a '+' to
|
||||
drop the assumption.
|
||||
|
||||
An L<Test2::Util::Trace> will be generated using C<caller(0)> and will be put in
|
||||
the 'trace' field of your new event, unless you specified your own 'trace'
|
||||
field.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
163
database/perl/vendor/lib/Test2/Tools/Exception.pm
vendored
Normal file
163
database/perl/vendor/lib/Test2/Tools/Exception.pm
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
package Test2::Tools::Exception;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Test2::API qw/context/;
|
||||
|
||||
our @EXPORT = qw/dies lives try_ok/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub dies(&) {
|
||||
my $code = shift;
|
||||
local ($@, $!, $?);
|
||||
my $ok = eval { $code->(); 1 };
|
||||
my $err = $@;
|
||||
|
||||
return undef if $ok;
|
||||
|
||||
unless ($err) {
|
||||
my $ctx = context();
|
||||
$ctx->alert("Got exception as expected, but exception is falsy (undef, '', or 0)...");
|
||||
$ctx->release;
|
||||
}
|
||||
|
||||
return $err;
|
||||
}
|
||||
|
||||
sub lives(&) {
|
||||
my $code = shift;
|
||||
|
||||
my $err;
|
||||
{
|
||||
local ($@, $!, $?);
|
||||
eval { $code->(); 1 } and return 1;
|
||||
$err = $@;
|
||||
}
|
||||
|
||||
# If the eval failed we want to set $@ to the error.
|
||||
$@ = $err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub try_ok(&;$) {
|
||||
my ($code, $name) = @_;
|
||||
|
||||
my $ok = &lives($code);
|
||||
my $err = $@;
|
||||
|
||||
# Context should be obtained AFTER code is run so that events inside the
|
||||
# codeblock report inside the codeblock itself. This will also preserve $@
|
||||
# as thrown inside the codeblock.
|
||||
my $ctx = context();
|
||||
chomp(my $diag = "Exception: $err");
|
||||
$ctx->ok($ok, $name, [$diag]);
|
||||
$ctx->release;
|
||||
|
||||
$@ = $err unless $ok;
|
||||
return $ok;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Exception - Test2 based tools for checking exceptions
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is the L<Test2> implementation of code used to test exceptions. This is
|
||||
similar to L<Test::Fatal>, but it intentionally does much less.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Exception qw/dies lives/;
|
||||
|
||||
like(
|
||||
dies { die 'xxx' },
|
||||
qr/xxx/,
|
||||
"Got exception"
|
||||
);
|
||||
|
||||
ok(lives { ... }, "did not die") or note($@);
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All subs are exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item $e = dies { ... }
|
||||
|
||||
This will trap any exception the codeblock throws. If no exception is thrown
|
||||
the sub will return undef. If an exception is thrown it will be returned. This
|
||||
function preserves C<$@>, it will not be altered from its value before the sub
|
||||
is called.
|
||||
|
||||
=item $bool = lives { ... }
|
||||
|
||||
This will trap any exception thrown in the codeblock. It will return true when
|
||||
there is no exception, and false when there is. C<$@> is preserved from before
|
||||
the sub is called when there is no exception. When an exception is trapped
|
||||
C<$@> will have the exception so that you can look at it.
|
||||
|
||||
=item $bool = try_ok { ... }
|
||||
|
||||
=item $bool = try_ok { ... } "Test Description"
|
||||
|
||||
This will run the code block trapping any exception. If there is no exception a
|
||||
passing event will be issued. If the test fails a failing event will be issued,
|
||||
and the exception will be reported as diagnostics.
|
||||
|
||||
B<Note:> This function does not preserve C<$@> on failure, it will be set to
|
||||
the exception the codeblock throws, this is by design so that you can obtain
|
||||
the exception if desired.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DIFFERENCES FROM TEST::FATAL
|
||||
|
||||
L<Test::Fatal> sets C<$Test::Builder::Level> such that failing tests inside the
|
||||
exception block will report to the line where C<exception()> is called. I
|
||||
disagree with this, and think the actual line of the failing test is
|
||||
more important. Ultimately, though L<Test::Fatal> cannot be changed, people
|
||||
probably already depend on that behavior.
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
169
database/perl/vendor/lib/Test2/Tools/Exports.pm
vendored
Normal file
169
database/perl/vendor/lib/Test2/Tools/Exports.pm
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
package Test2::Tools::Exports;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Carp qw/croak carp/;
|
||||
use Test2::API qw/context/;
|
||||
use Test2::Util::Stash qw/get_symbol/;
|
||||
|
||||
our @EXPORT = qw/imported_ok not_imported_ok/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub imported_ok {
|
||||
my $ctx = context();
|
||||
my $caller = caller;
|
||||
my @missing = grep { !get_symbol($_, $caller) } @_;
|
||||
|
||||
my $name = "Imported symbol";
|
||||
$name .= "s" if @_ > 1;
|
||||
$name .= ": ";
|
||||
my $list = join(", ", @_);
|
||||
substr($list, 37, length($list) - 37, '...') if length($list) > 40;
|
||||
$name .= $list;
|
||||
|
||||
$ctx->ok(!@missing, $name, [map { "'$_' was not imported." } @missing]);
|
||||
|
||||
$ctx->release;
|
||||
|
||||
return !@missing;
|
||||
}
|
||||
|
||||
sub not_imported_ok {
|
||||
my $ctx = context();
|
||||
my $caller = caller;
|
||||
my @found = grep { get_symbol($_, $caller) } @_;
|
||||
|
||||
my $name = "Did not imported symbol";
|
||||
$name .= "s" if @_ > 1;
|
||||
$name .= ": ";
|
||||
my $list = join(", ", @_);
|
||||
substr($list, 37, length($list) - 37, '...') if length($list) > 40;
|
||||
$name .= $list;
|
||||
|
||||
$ctx->ok(!@found, $name, [map { "'$_' was imported." } @found]);
|
||||
|
||||
$ctx->release;
|
||||
|
||||
return !@found;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Exports - Tools for validating exporters.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
These are tools for checking that symbols have been imported into your
|
||||
namespace.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Exports
|
||||
|
||||
use Data::Dumper;
|
||||
imported_ok qw/Dumper/;
|
||||
not_imported_ok qw/dumper/;
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All subs are exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item imported_ok(@SYMBOLS)
|
||||
|
||||
Check that the specified symbols exist in the current package. This will not
|
||||
find inherited subs. This will only find symbols in the current package's symbol
|
||||
table. This B<WILL NOT> confirm that the symbols were defined outside of the
|
||||
package itself.
|
||||
|
||||
imported_ok( '$scalar', '@array', '%hash', '&sub', 'also_a_sub' );
|
||||
|
||||
C<@SYMBOLS> can contain any number of symbols. Each item in the array must be a
|
||||
string. The string should be the name of a symbol. If a sigil is present then
|
||||
it will search for that specified type, if no sigil is specified it will be
|
||||
used as a sub name.
|
||||
|
||||
=item not_imported_ok(@SYMBOLS)
|
||||
|
||||
Check that the specified symbols do not exist in the current package. This will
|
||||
not find inherited subs. This will only look at symbols in the current package's
|
||||
symbol table.
|
||||
|
||||
not_imported_ok( '$scalar', '@array', '%hash', '&sub', 'also_a_sub' );
|
||||
|
||||
C<@SYMBOLS> can contain any number of symbols. Each item in the array must be a
|
||||
string. The string should be the name of a symbol. If a sigil is present, then
|
||||
it will search for that specified type. If no sigil is specified, it will be
|
||||
used as a sub name.
|
||||
|
||||
=back
|
||||
|
||||
=head1 CAVEATS
|
||||
|
||||
Before Perl 5.10, it is very difficult to distinguish between a package scalar
|
||||
that is undeclared vs declared and undefined. Currently C<imported_ok> and
|
||||
C<not_imported_ok> cannot see package scalars declared using C<our $var> unless
|
||||
the variable has been assigned a defined value.
|
||||
|
||||
This will pass on recent perls, but fail on perls older than 5.10:
|
||||
|
||||
use Test2::Tools::Exports;
|
||||
|
||||
our $foo;
|
||||
|
||||
# Fails on perl onlder than 5.10
|
||||
imported_ok(qw/$foo/);
|
||||
|
||||
If C<$foo> is imported from another module, or imported using
|
||||
C<use vars qw/$foo/;> then it will work on all supported perl versions.
|
||||
|
||||
use Test2::Tools::Exports;
|
||||
|
||||
use vars qw/$foo/;
|
||||
use Some::Module qw/$bar/;
|
||||
|
||||
# Always works
|
||||
imported_ok(qw/$foo $bar/);
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
125
database/perl/vendor/lib/Test2/Tools/GenTemp.pm
vendored
Normal file
125
database/perl/vendor/lib/Test2/Tools/GenTemp.pm
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
package Test2::Tools::GenTemp;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use File::Temp qw/tempdir/;
|
||||
use File::Spec;
|
||||
|
||||
our @EXPORT = qw{gen_temp};
|
||||
use base 'Exporter';
|
||||
|
||||
sub gen_temp {
|
||||
my %args = @_;
|
||||
|
||||
my $tempdir_args = delete $args{'-tempdir'} || [CLEANUP => 1, TMPDIR => 1];
|
||||
|
||||
my $tmp = tempdir(@$tempdir_args);
|
||||
|
||||
gen_dir($tmp, \%args);
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
sub gen_dir {
|
||||
my ($dir, $content) = @_;
|
||||
|
||||
for my $path (keys %$content) {
|
||||
my $fq = File::Spec->catfile($dir, $path);
|
||||
my $inside = $content->{$path};
|
||||
|
||||
if (ref $inside) {
|
||||
# Subdirectory
|
||||
mkdir($fq) or die "Could not make dir '$fq': $!";
|
||||
gen_dir($fq, $inside);
|
||||
}
|
||||
else {
|
||||
open(my $fh, '>', $fq) or die "Could not open file '$fq' for writing: $!";
|
||||
print $fh $inside;
|
||||
close($fh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::GenTemp - Tool for generating a populated temp directory.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This exports a tool that helps you make a temporary directory, nested
|
||||
directories and text files within.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::GenTemp qw/gen_temp/;
|
||||
|
||||
my $dir = gen_temp(
|
||||
a_file => "Contents of a_file",
|
||||
a_dir => {
|
||||
'a_file' => 'Contents of a_dir/afile',
|
||||
a_nested_dir => { ... },
|
||||
},
|
||||
...
|
||||
);
|
||||
|
||||
done_testing;
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All subs are exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item gen_temp(file => 'content', subdir => [ sub_dir_file => 'content', ...], ...)
|
||||
|
||||
=item gen_temp(-tempdir => \@TEMPDIR_ARGS, file => 'content', subdir => [ sub_dir_file => 'content', ...], ...)
|
||||
|
||||
This will generate a new temporary directory with all the files and subdirs you
|
||||
specify, recursively. The initial temp directory is created using
|
||||
C<File::Temp::tempdir()>, you may pass arguments to tempdir using the
|
||||
C<< -tempdir => [...] >> argument.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
124
database/perl/vendor/lib/Test2/Tools/Grab.pm
vendored
Normal file
124
database/perl/vendor/lib/Test2/Tools/Grab.pm
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
package Test2::Tools::Grab;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Test2::Util::Grabber;
|
||||
use Test2::EventFacet::Trace();
|
||||
|
||||
our @EXPORT = qw/grab/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub grab { Test2::Util::Grabber->new(trace => Test2::EventFacet::Trace->new(frame => [caller(0)]) ) }
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Grab - Temporarily intercept all events without adding a scope
|
||||
level.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This package provides a function that returns an object that grabs all events.
|
||||
Once the object is destroyed events will once again be sent to the main hub.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Grab;
|
||||
|
||||
my $grab = grab();
|
||||
|
||||
# Generate some events, they are intercepted.
|
||||
ok(1, "pass");
|
||||
ok(0, "fail");
|
||||
|
||||
my $events_a = $grab->flush;
|
||||
|
||||
# Generate some more events, they are intercepted.
|
||||
ok(1, "pass");
|
||||
ok(0, "fail");
|
||||
|
||||
my $events_b = $grab->finish;
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $grab = grab()
|
||||
|
||||
This lets you intercept all events for a section of code without adding
|
||||
anything to your call stack. This is useful for things that are sensitive to
|
||||
changes in the stack depth.
|
||||
|
||||
my $grab = grab();
|
||||
ok(1, 'foo');
|
||||
ok(0, 'bar');
|
||||
|
||||
my $events = $grab->finish;
|
||||
|
||||
is(@$events, 2, "grabbed 2 events.");
|
||||
|
||||
If the C<$grab> object is destroyed without calling C<finish()>, it will
|
||||
automatically clean up after itself and restore the parent hub.
|
||||
|
||||
{
|
||||
my $grab = grab();
|
||||
# Things are grabbed
|
||||
}
|
||||
# Things are back to normal
|
||||
|
||||
By default the hub used has C<no_ending> set to true. This will prevent the hub
|
||||
from enforcing that you issued a plan and ran at least 1 test. You can turn
|
||||
enforcement back one like this:
|
||||
|
||||
$grab->hub->set_no_ending(0);
|
||||
|
||||
With C<no_ending> turned off, C<finish> will run the post-test checks to
|
||||
enforce the plan and that tests were run. In many cases this will result in
|
||||
additional events in your events array.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Test2::Util::Grabber> - The object constructed and returned by this tool.
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2 can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
541
database/perl/vendor/lib/Test2/Tools/Mock.pm
vendored
Normal file
541
database/perl/vendor/lib/Test2/Tools/Mock.pm
vendored
Normal file
@@ -0,0 +1,541 @@
|
||||
package Test2::Tools::Mock;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Carp qw/croak/;
|
||||
use Scalar::Util qw/blessed reftype weaken/;
|
||||
use Test2::Util qw/try/;
|
||||
use Test2::Util::Sub qw/gen_accessor gen_reader gen_writer/;
|
||||
|
||||
use Test2::Mock();
|
||||
|
||||
use base 'Exporter';
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
our @CARP_NOT = (__PACKAGE__, 'Test2::Mock');
|
||||
our @EXPORT = qw/mock mocked/;
|
||||
our @EXPORT_OK = qw{
|
||||
mock_obj mock_class
|
||||
mock_do mock_build
|
||||
mock_accessor mock_accessors
|
||||
mock_getter mock_getters
|
||||
mock_setter mock_setters
|
||||
mock_building
|
||||
};
|
||||
|
||||
my %HANDLERS;
|
||||
my %MOCKS;
|
||||
my @BUILD;
|
||||
|
||||
sub add_handler {
|
||||
my $class = shift;
|
||||
my ($for, $code) = @_;
|
||||
|
||||
croak "Must specify a package for the mock handler"
|
||||
unless $for;
|
||||
|
||||
croak "Handlers must be code referneces (got: $code)"
|
||||
unless $code && ref($code) eq 'CODE';
|
||||
|
||||
push @{$HANDLERS{$for}} => $code;
|
||||
}
|
||||
|
||||
sub mock_building {
|
||||
return unless @BUILD;
|
||||
return $BUILD[-1];
|
||||
}
|
||||
|
||||
sub mocked {
|
||||
my $proto = shift;
|
||||
my $class = blessed($proto) || $proto;
|
||||
|
||||
# Check if we have any mocks.
|
||||
my $set = $MOCKS{$class} || return;
|
||||
|
||||
# Remove dead mocks (undef due to weaken)
|
||||
pop @$set while @$set && !defined($set->[-1]);
|
||||
|
||||
# Remove the list if it is empty
|
||||
delete $MOCKS{$class} unless @$set;
|
||||
|
||||
# Return the controls (may be empty list)
|
||||
return @$set;
|
||||
}
|
||||
|
||||
sub _delegate {
|
||||
my ($args) = @_;
|
||||
|
||||
my $do = __PACKAGE__->can('mock_do');
|
||||
my $obj = __PACKAGE__->can('mock_obj');
|
||||
my $class = __PACKAGE__->can('mock_class');
|
||||
my $build = __PACKAGE__->can('mock_build');
|
||||
|
||||
return $obj unless @$args;
|
||||
|
||||
my ($proto, $arg1) = @$args;
|
||||
|
||||
return $obj if ref($proto) && !blessed($proto);
|
||||
|
||||
if (blessed($proto)) {
|
||||
return $class unless $proto->isa('Test2::Mock');
|
||||
return $build if $arg1 && ref($arg1) && reftype($arg1) eq 'CODE';
|
||||
}
|
||||
|
||||
return $class if $proto =~ m/(?:::|')/;
|
||||
return $class if $proto =~ m/^_*[A-Z]/;
|
||||
|
||||
return $do if Test2::Mock->can($proto);
|
||||
|
||||
if (my $sub = __PACKAGE__->can("mock_$proto")) {
|
||||
shift @$args;
|
||||
return $sub;
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub mock {
|
||||
croak "undef is not a valid first argument to mock()"
|
||||
if @_ && !defined($_[0]);
|
||||
|
||||
my $sub = _delegate(\@_);
|
||||
|
||||
croak "'$_[0]' does not look like a package name, and is not a valid control method"
|
||||
unless $sub;
|
||||
|
||||
$sub->(@_);
|
||||
}
|
||||
|
||||
sub mock_build {
|
||||
my ($control, $sub) = @_;
|
||||
|
||||
croak "mock_build requires a Test2::Mock object as its first argument"
|
||||
unless $control && blessed($control) && $control->isa('Test2::Mock');
|
||||
|
||||
croak "mock_build requires a coderef as its second argument"
|
||||
unless $sub && ref($sub) && reftype($sub) eq 'CODE';
|
||||
|
||||
push @BUILD => $control;
|
||||
my ($ok, $err) = &try($sub);
|
||||
pop @BUILD;
|
||||
die $err unless $ok;
|
||||
}
|
||||
|
||||
sub mock_do {
|
||||
my ($meth, @args) = @_;
|
||||
|
||||
croak "Not currently building a mock"
|
||||
unless @BUILD;
|
||||
|
||||
my $build = $BUILD[-1];
|
||||
|
||||
croak "'$meth' is not a valid action for mock_do()"
|
||||
if $meth =~ m/^_/ || !$build->can($meth);
|
||||
|
||||
$build->$meth(@args);
|
||||
}
|
||||
|
||||
sub mock_obj {
|
||||
my ($proto) = @_;
|
||||
|
||||
if ($proto && ref($proto) && reftype($proto) ne 'CODE') {
|
||||
shift @_;
|
||||
}
|
||||
else {
|
||||
$proto = {};
|
||||
}
|
||||
|
||||
my $class = _generate_class();
|
||||
my $control;
|
||||
|
||||
if (@_ == 1 && reftype($_[0]) eq 'CODE') {
|
||||
my $orig = shift @_;
|
||||
$control = mock_class(
|
||||
$class,
|
||||
sub {
|
||||
my $c = mock_building;
|
||||
|
||||
# We want to do these BEFORE anything that the sub may do.
|
||||
$c->block_load(1);
|
||||
$c->purge_on_destroy(1);
|
||||
$c->autoload(1);
|
||||
|
||||
$orig->(@_);
|
||||
},
|
||||
);
|
||||
}
|
||||
else {
|
||||
$control = mock_class(
|
||||
$class,
|
||||
# Do these before anything the user specified.
|
||||
block_load => 1,
|
||||
purge_on_destroy => 1,
|
||||
autoload => 1,
|
||||
@_,
|
||||
);
|
||||
}
|
||||
|
||||
my $new = bless($proto, $control->class);
|
||||
|
||||
# We need to ensure there is a reference to the control object, and we want
|
||||
# it to go away with the object.
|
||||
$new->{'~~MOCK~CONTROL~~'} = $control;
|
||||
return $new;
|
||||
}
|
||||
|
||||
sub _generate_class {
|
||||
my $prefix = __PACKAGE__;
|
||||
|
||||
for (1 .. 100) {
|
||||
my $postfix = join '', map { chr(rand(26) + 65) } 1 .. 32;
|
||||
my $class = $prefix . '::__TEMP__::' . $postfix;
|
||||
my $file = $class;
|
||||
$file =~ s{::}{/}g;
|
||||
$file .= '.pm';
|
||||
next if $INC{$file};
|
||||
my $stash = do { no strict 'refs'; \%{"${class}\::"} };
|
||||
next if keys %$stash;
|
||||
return $class;
|
||||
}
|
||||
|
||||
croak "Could not generate a unique class name after 100 attempts";
|
||||
}
|
||||
|
||||
sub mock_class {
|
||||
my $proto = shift;
|
||||
my $class = blessed($proto) || $proto;
|
||||
my @args = @_;
|
||||
|
||||
my $void = !defined(wantarray);
|
||||
|
||||
my $callback = sub {
|
||||
my ($parent) = reverse mocked($class);
|
||||
my $control;
|
||||
|
||||
if (@args == 1 && ref($args[0]) && reftype($args[0]) eq 'CODE') {
|
||||
$control = Test2::Mock->new(class => $class);
|
||||
mock_build($control, @args);
|
||||
}
|
||||
else {
|
||||
$control = Test2::Mock->new(class => $class, @args);
|
||||
}
|
||||
|
||||
if ($parent) {
|
||||
$control->{parent} = $parent;
|
||||
weaken($parent->{child} = $control);
|
||||
}
|
||||
|
||||
$MOCKS{$class} ||= [];
|
||||
push @{$MOCKS{$class}} => $control;
|
||||
weaken($MOCKS{$class}->[-1]);
|
||||
|
||||
return $control;
|
||||
};
|
||||
|
||||
return $callback->() unless $void;
|
||||
|
||||
my $level = 0;
|
||||
my $caller;
|
||||
while (my @call = caller($level++)) {
|
||||
next if $call[0] eq __PACKAGE__;
|
||||
$caller = \@call;
|
||||
last;
|
||||
}
|
||||
|
||||
my $handled;
|
||||
for my $handler (@{$HANDLERS{$caller->[0]}}) {
|
||||
$handled++ if $handler->(
|
||||
class => $class,
|
||||
caller => $caller,
|
||||
builder => $callback,
|
||||
args => \@args,
|
||||
);
|
||||
}
|
||||
|
||||
croak "mock_class should not be called in a void context without a registered handler"
|
||||
unless $handled;
|
||||
}
|
||||
|
||||
sub mock_accessors {
|
||||
return map {( $_ => gen_accessor($_) )} @_;
|
||||
}
|
||||
|
||||
sub mock_accessor {
|
||||
my ($field) = @_;
|
||||
return gen_accessor($field);
|
||||
}
|
||||
|
||||
sub mock_getters {
|
||||
my ($prefix, @list) = @_;
|
||||
return map {( "$prefix$_" => gen_reader($_) )} @list;
|
||||
}
|
||||
|
||||
sub mock_getter {
|
||||
my ($field) = @_;
|
||||
return gen_reader($field);
|
||||
}
|
||||
|
||||
sub mock_setters {
|
||||
my ($prefix, @list) = @_;
|
||||
return map {( "$prefix$_" => gen_writer($_) )} @list;
|
||||
}
|
||||
|
||||
sub mock_setter {
|
||||
my ($field) = @_;
|
||||
return gen_writer($field);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Mock - Class/Instance mocking for Test2.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Mocking is often an essential part of testing. This library covers some of the
|
||||
most common mocking needs. This plugin is heavily influenced by L<Mock::Quick>,
|
||||
but with an improved API. This plugin is also intended to play well with other
|
||||
plugins in ways L<Mock::Quick> would be unable to.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
my $mock = mock 'Some::Class' => (
|
||||
track => $BOOL, # Enable/Disable tracking on subs defined below
|
||||
|
||||
add => [
|
||||
new_method => sub { ... },
|
||||
],
|
||||
override => [
|
||||
replace_method => sub { ... },
|
||||
],
|
||||
set => [
|
||||
replace_or_inject => sub { ... },
|
||||
],
|
||||
|
||||
track => $bool, # enable/disable tracking again to affect mocks made after this point
|
||||
..., # Argument keys may be repeated
|
||||
);
|
||||
|
||||
Some::Class->new_method(); # Calls the newly injected method
|
||||
Some::Class->replace_method(); # Calls our replacement method.
|
||||
|
||||
$mock->override(...) # Override some more
|
||||
|
||||
$mock = undef; # Undoes all the mocking, restoring all original methods.
|
||||
|
||||
my $simple_mock = mock {} => (
|
||||
add => [
|
||||
is_active => sub { ... }
|
||||
]
|
||||
);
|
||||
|
||||
$simple_mock->is_active(); # Calls our newly mocked method.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
=head2 DEFAULT
|
||||
|
||||
=over 4
|
||||
|
||||
=item mock
|
||||
|
||||
This is a one-stop shop function that delegates to one of the other methods
|
||||
depending on how it is used. If you are not comfortable with a function that
|
||||
has a lot of potential behaviors, you can use one of the other functions
|
||||
directly.
|
||||
|
||||
=item @mocks = mocked($object)
|
||||
|
||||
=item @mocks = mocked($class)
|
||||
|
||||
Check if an object or class is mocked. If it is mocked the C<$mock> object(s)
|
||||
(L<Test2::Mock>) will be returned.
|
||||
|
||||
=item $mock = mock $class => ( ... );
|
||||
|
||||
=item $mock = mock $instance => ( ... )
|
||||
|
||||
=item $mock = mock 'class', $class => ( ... )
|
||||
|
||||
These forms delegate to C<mock_class()> to mock a package. The third form is to
|
||||
be explicit about what type of mocking you want.
|
||||
|
||||
=item $obj = mock()
|
||||
|
||||
=item $obj = mock { ... }
|
||||
|
||||
=item $obj = mock 'obj', ...;
|
||||
|
||||
These forms delegate to C<mock_obj()> to create instances of anonymous packages
|
||||
where methods are vivified into existence as needed.
|
||||
|
||||
=item mock $mock => sub { ... }
|
||||
|
||||
=item mock $method => ( ... )
|
||||
|
||||
These forms go together, the first form will set C<$mock> as the current mock
|
||||
build, then run the sub. Within the sub you can declare mock specifications
|
||||
using the second form. The first form delegates to C<mock_build()>.
|
||||
|
||||
The second form calls the specified method on the current build. This second
|
||||
form delegates to C<mock_do()>.
|
||||
|
||||
=back
|
||||
|
||||
=head2 BY REQUEST
|
||||
|
||||
=head3 DEFINING MOCKS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $obj = mock_obj( ... )
|
||||
|
||||
=item $obj = mock_obj { ... } => ( ... )
|
||||
|
||||
=item $obj = mock_obj sub { ... }
|
||||
|
||||
=item $obj = mock_obj { ... } => sub { ... }
|
||||
|
||||
This method lets you quickly generate a blessed object. The object will be an
|
||||
instance of a randomly generated package name. Methods will vivify as
|
||||
read/write accessors as needed.
|
||||
|
||||
Arguments can be any method available to L<Test2::Mock> followed by an
|
||||
argument. If the very first argument is a hashref then it will be blessed as
|
||||
your new object.
|
||||
|
||||
If you provide a coderef instead of key/value pairs, the coderef will be run to
|
||||
build the mock. (See the L</"BUILDING MOCKS"> section).
|
||||
|
||||
=item $mock = mock_class $class => ( ... )
|
||||
|
||||
=item $mock = mock_class $instance => ( ... )
|
||||
|
||||
=item $mock = mock_class ... => sub { ... }
|
||||
|
||||
This will create a new instance of L<Test2::Mock> to control the package
|
||||
specified. If you give it a blessed reference it will use the class of the
|
||||
instance.
|
||||
|
||||
Arguments can be any method available to L<Test2::Mock> followed by an
|
||||
argument. If the very first argument is a hashref then it will be blessed as
|
||||
your new object.
|
||||
|
||||
If you provide a coderef instead of key/value pairs, the coderef will be run to
|
||||
build the mock. (See the L</"BUILDING MOCKS"> section).
|
||||
|
||||
=back
|
||||
|
||||
=head3 BUILDING MOCKS
|
||||
|
||||
=over 4
|
||||
|
||||
=item mock_build $mock => sub { ... }
|
||||
|
||||
Set C<$mock> as the current build, then run the specified code. C<$mock> will
|
||||
no longer be the current build when the sub is complete.
|
||||
|
||||
=item $mock = mock_building()
|
||||
|
||||
Get the current building C<$mock> object.
|
||||
|
||||
=item mock_do $method => $args
|
||||
|
||||
Run the specified method on the currently building object.
|
||||
|
||||
=back
|
||||
|
||||
=head3 METHOD GENERATORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $sub = mock_accessor $field
|
||||
|
||||
Generate a read/write accessor for the specified field. This will generate a sub like the following:
|
||||
|
||||
$sub = sub {
|
||||
my $self = shift;
|
||||
($self->{$field}) = @_ if @_;
|
||||
return $self->{$field};
|
||||
};
|
||||
|
||||
=item $sub = mock_getter $field
|
||||
|
||||
Generate a read only accessor for the specified field. This will generate a sub like the following:
|
||||
|
||||
$sub = sub {
|
||||
my $self = shift;
|
||||
return $self->{$field};
|
||||
};
|
||||
|
||||
=item $sub = mock_setter $field
|
||||
|
||||
Generate a write accessor for the specified field. This will generate a sub like the following:
|
||||
|
||||
$sub = sub {
|
||||
my $self = shift;
|
||||
($self->{$field}) = @_;
|
||||
};
|
||||
|
||||
=item %pairs = mock_accessors(qw/name1 name2 name3/)
|
||||
|
||||
Generates several read/write accessors at once, returns key/value pairs where
|
||||
the key is the field name, and the value is the coderef.
|
||||
|
||||
=item %pairs = mock_getters(qw/name1 name2 name3/)
|
||||
|
||||
Generates several read only accessors at once, returns key/value pairs where
|
||||
the key is the field name, and the value is the coderef.
|
||||
|
||||
=item %pairs = mock_setters(qw/name1 name2 name3/)
|
||||
|
||||
Generates several write accessors at once, returns key/value pairs where the
|
||||
key is the field name, and the value is the coderef.
|
||||
|
||||
=back
|
||||
|
||||
=head1 MOCK CONTROL OBJECTS
|
||||
|
||||
my $mock = mock(...);
|
||||
|
||||
Mock objects are instances of L<Test2::Mock>. See it for their methods.
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
L<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See L<https://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
173
database/perl/vendor/lib/Test2/Tools/Ref.pm
vendored
Normal file
173
database/perl/vendor/lib/Test2/Tools/Ref.pm
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package Test2::Tools::Ref;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Scalar::Util qw/reftype refaddr/;
|
||||
use Test2::API qw/context/;
|
||||
use Test2::Util::Ref qw/render_ref/;
|
||||
|
||||
our @EXPORT = qw/ref_ok ref_is ref_is_not/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub ref_ok($;$$) {
|
||||
my ($thing, $wanttype, $name) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
my $gotname = render_ref($thing);
|
||||
my $gottype = reftype($thing);
|
||||
|
||||
if (!$gottype) {
|
||||
$ctx->ok(0, $name, ["'$gotname' is not a reference"]);
|
||||
$ctx->release;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($wanttype && $gottype ne $wanttype) {
|
||||
$ctx->ok(0, $name, ["'$gotname' is not a '$wanttype' reference"]);
|
||||
$ctx->release;
|
||||
return 0;
|
||||
}
|
||||
|
||||
$ctx->ok(1, $name);
|
||||
$ctx->release;
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub ref_is($$;$@) {
|
||||
my ($got, $exp, $name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
$got = '<undef>' unless defined $got;
|
||||
$exp = '<undef>' unless defined $exp;
|
||||
|
||||
my $bool = 0;
|
||||
if (!ref($got)) {
|
||||
$ctx->ok(0, $name, ["First argument '$got' is not a reference", @diag]);
|
||||
}
|
||||
elsif(!ref($exp)) {
|
||||
$ctx->ok(0, $name, ["Second argument '$exp' is not a reference", @diag]);
|
||||
}
|
||||
else {
|
||||
# Don't let overloading mess with us.
|
||||
$bool = refaddr($got) == refaddr($exp);
|
||||
$ctx->ok($bool, $name, ["'$got' is not the same reference as '$exp'", @diag]);
|
||||
}
|
||||
|
||||
$ctx->release;
|
||||
return $bool ? 1 : 0;
|
||||
}
|
||||
|
||||
sub ref_is_not($$;$) {
|
||||
my ($got, $exp, $name, @diag) = @_;
|
||||
my $ctx = context();
|
||||
|
||||
$got = '<undef>' unless defined $got;
|
||||
$exp = '<undef>' unless defined $exp;
|
||||
|
||||
my $bool = 0;
|
||||
if (!ref($got)) {
|
||||
$ctx->ok(0, $name, ["First argument '$got' is not a reference", @diag]);
|
||||
}
|
||||
elsif(!ref($exp)) {
|
||||
$ctx->ok(0, $name, ["Second argument '$exp' is not a reference", @diag]);
|
||||
}
|
||||
else {
|
||||
# Don't let overloading mess with us.
|
||||
$bool = refaddr($got) != refaddr($exp);
|
||||
$ctx->ok($bool, $name, ["'$got' is the same reference as '$exp'", @diag]);
|
||||
}
|
||||
|
||||
$ctx->release;
|
||||
return $bool ? 1 : 0;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Ref - Tools for validating references.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains tools that allow you to verify that something is a ref. It
|
||||
also has tools to check if two refs are the same exact ref, or different. None of
|
||||
the functions in this module do deep comparisons.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Ref;
|
||||
|
||||
# Ensure something is a ref.
|
||||
ref_ok($ref);
|
||||
|
||||
# Check that $ref is a HASH reference
|
||||
ref_ok($ref, 'HASH', 'Must be a hash')
|
||||
|
||||
ref_is($refa, $refb, "Same exact reference");
|
||||
|
||||
ref_is_not($refa, $refb, "Not the same exact reference");
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All subs are exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item ref_ok($thing)
|
||||
|
||||
=item ref_ok($thing, $type)
|
||||
|
||||
=item ref_ok($thing, $type, $name)
|
||||
|
||||
This checks that C<$thing> is a reference. If C<$type> is specified then it
|
||||
will check that C<$thing> is that type of reference.
|
||||
|
||||
=item ref_is($ref1, $ref2, $name)
|
||||
|
||||
Verify that two references are the exact same reference.
|
||||
|
||||
=item ref_is_not($ref1, $ref2, $name)
|
||||
|
||||
Verify that two references are not the exact same reference.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
676
database/perl/vendor/lib/Test2/Tools/Spec.pm
vendored
Normal file
676
database/perl/vendor/lib/Test2/Tools/Spec.pm
vendored
Normal file
@@ -0,0 +1,676 @@
|
||||
package Test2::Tools::Spec;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Carp qw/croak/;
|
||||
use Test2::Workflow qw/parse_args build current_build root_build init_root build_stack/;
|
||||
|
||||
use Test2::API qw/test2_add_callback_testing_done/;
|
||||
|
||||
use Test2::Workflow::Runner();
|
||||
use Test2::Workflow::Task::Action();
|
||||
use Test2::Workflow::Task::Group();
|
||||
use Test2::Tools::Mock();
|
||||
use Importer();
|
||||
|
||||
use vars qw/@EXPORT @EXPORT_OK/;
|
||||
push @EXPORT => qw{describe cases};
|
||||
push @EXPORT_OK => qw{include_workflow include_workflows spec_defaults};
|
||||
|
||||
my %HANDLED;
|
||||
sub import {
|
||||
my $class = shift;
|
||||
my @caller = caller(0);
|
||||
|
||||
my %root_args;
|
||||
my %runner_args;
|
||||
my @import;
|
||||
while (my $arg = shift @_) {
|
||||
if ($arg =~ s/^-//) {
|
||||
my $val = shift @_;
|
||||
|
||||
if (Test2::Workflow::Runner->can($arg)) {
|
||||
$runner_args{$arg} = $val;
|
||||
}
|
||||
elsif (Test2::Workflow::Task::Group->can($arg)) {
|
||||
$root_args{$arg} = $val;
|
||||
}
|
||||
elsif ($arg eq 'root_args') {
|
||||
%root_args = (%root_args, %$val);
|
||||
}
|
||||
elsif ($arg eq 'runner_args') {
|
||||
%runner_args = (%runner_args, %$val);
|
||||
}
|
||||
else {
|
||||
croak "Unrecognized arg: $arg";
|
||||
}
|
||||
}
|
||||
else {
|
||||
push @import => $arg;
|
||||
}
|
||||
}
|
||||
|
||||
if ($HANDLED{$caller[0]}++) {
|
||||
croak "Package $caller[0] has already been initialized"
|
||||
if keys(%root_args) || keys(%runner_args);
|
||||
}
|
||||
else {
|
||||
my $root = init_root(
|
||||
$caller[0],
|
||||
frame => \@caller,
|
||||
code => sub { 1 },
|
||||
%root_args,
|
||||
);
|
||||
|
||||
my $runner = Test2::Workflow::Runner->new(%runner_args);
|
||||
|
||||
Test2::Tools::Mock->add_handler(
|
||||
$caller[0],
|
||||
sub {
|
||||
my %params = @_;
|
||||
my ($class, $caller, $builder, $args) = @params{qw/class caller builder args/};
|
||||
|
||||
my $do_it = eval "package $caller->[0];\n#line $caller->[2] \"$caller->[1]\"\nsub { \$runner\->add_mock(\$builder->()) }";
|
||||
|
||||
# Running
|
||||
if (@{$runner->stack}) {
|
||||
$do_it->();
|
||||
}
|
||||
else { # Not running
|
||||
my $action = Test2::Workflow::Task::Action->new(
|
||||
code => $do_it,
|
||||
name => "mock $class",
|
||||
frame => $caller,
|
||||
scaffold => 1,
|
||||
);
|
||||
|
||||
my $build = current_build() || $root;
|
||||
|
||||
$build->add_primary_setup($action);
|
||||
$build->add_stash($builder->()) unless $build->is_root;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
);
|
||||
|
||||
test2_add_callback_testing_done(
|
||||
sub {
|
||||
return unless $root->populated;
|
||||
my $g = $root->compile;
|
||||
$runner->push_task($g);
|
||||
$runner->run;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Importer->import_into($class, $caller[0], @import);
|
||||
}
|
||||
|
||||
{
|
||||
no warnings 'once';
|
||||
*cases = \&describe;
|
||||
*include_workflows = \&include_workflow;
|
||||
}
|
||||
|
||||
sub describe {
|
||||
my @caller = caller(0);
|
||||
|
||||
my $want = wantarray;
|
||||
|
||||
my $build = build(args => \@_, caller => \@caller, stack_stop => defined $want ? 1 : 0);
|
||||
|
||||
return $build if defined $want;
|
||||
|
||||
my $current = current_build() || root_build($caller[0])
|
||||
or croak "No current workflow build!";
|
||||
|
||||
$current->add_primary($build);
|
||||
}
|
||||
|
||||
sub include_workflow {
|
||||
my @caller = caller(0);
|
||||
|
||||
my $build = current_build() || root_build(\$caller[0])
|
||||
or croak "No current workflow build!";
|
||||
|
||||
for my $task (@_) {
|
||||
croak "include_workflow only accepts Test2::Workflow::Task objects, got: $task"
|
||||
unless $task->isa('Test2::Workflow::Task');
|
||||
|
||||
$build->add_primary($task);
|
||||
}
|
||||
}
|
||||
|
||||
sub defaults {
|
||||
my %params = @_;
|
||||
|
||||
my ($package, $tool) = @params{qw/package tool/};
|
||||
|
||||
my @stack = (root_build($package), build_stack());
|
||||
return unless @stack;
|
||||
|
||||
my %out;
|
||||
for my $build (@stack) {
|
||||
%out = () if $build->stack_stop;
|
||||
my $new = $build->defaults->{$tool} or next;
|
||||
%out = (%out, %$new);
|
||||
}
|
||||
|
||||
return \%out;
|
||||
}
|
||||
|
||||
|
||||
# Generate a bunch of subs that only have minor differences between them.
|
||||
BEGIN {
|
||||
@EXPORT = qw{
|
||||
tests it
|
||||
case
|
||||
before_all around_all after_all
|
||||
before_case around_case after_case
|
||||
before_each around_each after_each
|
||||
};
|
||||
|
||||
@EXPORT_OK = qw{
|
||||
mini
|
||||
iso miso
|
||||
async masync
|
||||
};
|
||||
|
||||
my %stages = (
|
||||
case => ['add_variant'],
|
||||
tests => ['add_primary'],
|
||||
it => ['add_primary'],
|
||||
|
||||
iso => ['add_primary'],
|
||||
miso => ['add_primary'],
|
||||
|
||||
async => ['add_primary'],
|
||||
masync => ['add_primary'],
|
||||
|
||||
mini => ['add_primary'],
|
||||
|
||||
before_all => ['add_setup'],
|
||||
after_all => ['add_teardown'],
|
||||
around_all => ['add_setup', 'add_teardown'],
|
||||
|
||||
before_case => ['add_variant_setup'],
|
||||
after_case => ['add_variant_teardown'],
|
||||
around_case => ['add_variant_setup', 'add_variant_teardown'],
|
||||
|
||||
before_each => ['add_primary_setup'],
|
||||
after_each => ['add_primary_teardown'],
|
||||
around_each => ['add_primary_setup', 'add_primary_teardown'],
|
||||
);
|
||||
|
||||
my %props = (
|
||||
case => [],
|
||||
tests => [],
|
||||
it => [],
|
||||
|
||||
iso => [iso => 1],
|
||||
miso => [iso => 1, flat => 1],
|
||||
|
||||
async => [async => 1],
|
||||
masync => [async => 1, flat => 1],
|
||||
|
||||
mini => [flat => 1],
|
||||
|
||||
before_all => [scaffold => 1],
|
||||
after_all => [scaffold => 1],
|
||||
around_all => [scaffold => 1, around => 1],
|
||||
|
||||
before_case => [scaffold => 1],
|
||||
after_case => [scaffold => 1],
|
||||
around_case => [scaffold => 1, around => 1],
|
||||
|
||||
before_each => [scaffold => 1],
|
||||
after_each => [scaffold => 1],
|
||||
around_each => [scaffold => 1, around => 1],
|
||||
);
|
||||
|
||||
sub spec_defaults {
|
||||
my ($tool, %params) = @_;
|
||||
my @caller = caller(0);
|
||||
|
||||
croak "'$tool' is not a spec tool"
|
||||
unless exists $props{$tool} || exists $stages{$tool};
|
||||
|
||||
my $build = current_build() || root_build($caller[0])
|
||||
or croak "No current workflow build!";
|
||||
|
||||
my $old = $build->defaults->{$tool} ||= {};
|
||||
$build->defaults->{$tool} = { %$old, %params };
|
||||
}
|
||||
|
||||
my $run = "";
|
||||
for my $func (@EXPORT, @EXPORT_OK) {
|
||||
$run .= <<" EOT";
|
||||
#line ${ \(__LINE__ + 1) } "${ \__FILE__ }"
|
||||
sub $func {
|
||||
my \@caller = caller(0);
|
||||
my \$args = parse_args(args => \\\@_, caller => \\\@caller);
|
||||
my \$action = Test2::Workflow::Task::Action->new(\@{\$props{$func}}, %\$args);
|
||||
|
||||
return \$action if defined wantarray;
|
||||
|
||||
my \$build = current_build() || root_build(\$caller[0])
|
||||
or croak "No current workflow build!";
|
||||
|
||||
if (my \$defaults = defaults(package => \$caller[0], tool => '$func')) {
|
||||
for my \$attr (keys \%\$defaults) {
|
||||
next if defined \$action->\$attr;
|
||||
my \$sub = "set_\$attr";
|
||||
\$action->\$sub(\$defaults->{\$attr});
|
||||
}
|
||||
}
|
||||
|
||||
\$build->\$_(\$action) for \@{\$stages{$func}};
|
||||
}
|
||||
EOT
|
||||
}
|
||||
|
||||
my ($ok, $err);
|
||||
{
|
||||
local $@;
|
||||
$ok = eval "$run\n1";
|
||||
$err = $@;
|
||||
}
|
||||
|
||||
die $@ unless $ok;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Spec - RSPEC implementation on top of Test2::Workflow
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This uses L<Test2::Workflow> to implement an RSPEC variant. This variant
|
||||
supports isolation and/or concurrency via forking or threads.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Bundle::Extended;
|
||||
use Test2::Tools::Spec;
|
||||
|
||||
describe foo => sub {
|
||||
before_all once => sub { ... };
|
||||
before_each many => sub { ... };
|
||||
|
||||
after_all once => sub { ... };
|
||||
after_each many => sub { ... };
|
||||
|
||||
case condition_a => sub { ... };
|
||||
case condition_b => sub { ... };
|
||||
|
||||
tests foo => sub { ... };
|
||||
tests bar => sub { ... };
|
||||
};
|
||||
|
||||
done_testing;
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All of these use the same argument pattern. The first argument must always be a
|
||||
name for the block. The last argument must always be a code reference.
|
||||
Optionally a configuration hash can be inserted between the name and the code
|
||||
reference.
|
||||
|
||||
FUNCTION "name" => sub { ... };
|
||||
|
||||
FUNCTION "name" => {...}, sub { ... };
|
||||
|
||||
=over 4
|
||||
|
||||
=item NAME
|
||||
|
||||
The first argument to a Test2::Tools::Spec function MUST be a name. The name
|
||||
does not need to be unique.
|
||||
|
||||
=item PARAMS
|
||||
|
||||
This argument is optional. If present this should be a hashref.
|
||||
|
||||
Here are the valid keys for the hashref:
|
||||
|
||||
=over 8
|
||||
|
||||
=item flat => $bool
|
||||
|
||||
If this is set to true then the block will not render as a subtest, instead the
|
||||
events will be inline with the parent subtest (or main test).
|
||||
|
||||
=item async => $bool
|
||||
|
||||
Set this to true to mark a block as being capable of running concurrently with
|
||||
other test blocks. This does not mean the block WILL be run concurrently, just
|
||||
that it can be.
|
||||
|
||||
=item iso => $bool
|
||||
|
||||
Set this to true if the block MUST be run in isolation. If this is true then
|
||||
the block will run in its own forked process.
|
||||
|
||||
These tests will be skipped on any platform that does not have true forking, or
|
||||
working/enabled threads.
|
||||
|
||||
Threads will ONLY be used if the T2_WORKFLOW_USE_THREADS env var is set. Thread
|
||||
tests are only run if the T2_DO_THREAD_TESTS env var is set.
|
||||
|
||||
=item todo => $reason
|
||||
|
||||
Use this to mark an entire block as TODO.
|
||||
|
||||
=item skip => $reason
|
||||
|
||||
Use this to prevent a block from running at all.
|
||||
|
||||
=back
|
||||
|
||||
=item CODEREF
|
||||
|
||||
This argument is required. This should be a code reference that will run some
|
||||
assertions.
|
||||
|
||||
=back
|
||||
|
||||
=head2 ESSENTIALS
|
||||
|
||||
=over 4
|
||||
|
||||
=item tests NAME => sub { ... }
|
||||
|
||||
=item tests NAME => \%params, sub { ... }
|
||||
|
||||
=item tests($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
=item it NAME => sub { ... }
|
||||
|
||||
=item it NAME => \%params, sub { ... }
|
||||
|
||||
=item it($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
This defines a test block. Test blocks are essentially subtests. All test
|
||||
blocks will be run, and are expected to produce events. Test blocks can run
|
||||
multiple times if the C<case()> function is also used.
|
||||
|
||||
C<it()> is an alias to C<tests()>.
|
||||
|
||||
These ARE NOT inherited by nested describe blocks.
|
||||
|
||||
=item case NAME => sub { ... }
|
||||
|
||||
=item case NAME => \%params, sub { ... }
|
||||
|
||||
=item case($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
This lets you specify multiple conditions in which the test blocks should be
|
||||
run. Every test block within the same group (C<describe>) will be run once per
|
||||
case.
|
||||
|
||||
These ARE NOT inherited by nested describe blocks, but nested describe blocks
|
||||
will be executed once per case.
|
||||
|
||||
=item before_each NAME => sub { ... }
|
||||
|
||||
=item before_each NAME => \%params, sub { ... }
|
||||
|
||||
=item before_each($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Specify a codeblock that should be run multiple times, once before each
|
||||
C<tests()> block is run. These will run AFTER C<case()> blocks but before
|
||||
C<tests()> blocks.
|
||||
|
||||
These ARE inherited by nested describe blocks.
|
||||
|
||||
=item before_case NAME => sub { ... }
|
||||
|
||||
=item before_case NAME => \%params, sub { ... }
|
||||
|
||||
=item before_case($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Same as C<before_each()>, except these blocks run BEFORE C<case()> blocks.
|
||||
|
||||
These ARE NOT inherited by nested describe blocks.
|
||||
|
||||
=item before_all NAME => sub { ... }
|
||||
|
||||
=item before_all NAME => \%params, sub { ... }
|
||||
|
||||
=item before_all($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Specify a codeblock that should be run once, before all the test blocks run.
|
||||
|
||||
These ARE NOT inherited by nested describe blocks.
|
||||
|
||||
=item around_each NAME => sub { ... }
|
||||
|
||||
=item around_each NAME => \%params, sub { ... }
|
||||
|
||||
=item around_each($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Specify a codeblock that should wrap around each test block. These blocks are
|
||||
run AFTER case blocks, but before test blocks.
|
||||
|
||||
around_each wrapit => sub {
|
||||
my $cont = shift;
|
||||
|
||||
local %ENV = ( ... );
|
||||
|
||||
$cont->();
|
||||
|
||||
...
|
||||
};
|
||||
|
||||
The first argument to the codeblock will be a callback that MUST be called
|
||||
somewhere inside the sub in order for nested items to run.
|
||||
|
||||
These ARE inherited by nested describe blocks.
|
||||
|
||||
=item around_case NAME => sub { ... }
|
||||
|
||||
=item around_case NAME => \%params, sub { ... }
|
||||
|
||||
=item around_case($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Same as C<around_each> except these run BEFORE case blocks.
|
||||
|
||||
These ARE NOT inherited by nested describe blocks.
|
||||
|
||||
=item around_all NAME => sub { ... }
|
||||
|
||||
=item around_all NAME => \%params, sub { ... }
|
||||
|
||||
=item around_all($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Same as C<around_each> except that it only runs once to wrap ALL test blocks.
|
||||
|
||||
These ARE NOT inherited by nested describe blocks.
|
||||
|
||||
=item after_each NAME => sub { ... }
|
||||
|
||||
=item after_each NAME => \%params, sub { ... }
|
||||
|
||||
=item after_each($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Same as C<before_each> except it runs right after each test block.
|
||||
|
||||
These ARE inherited by nested describe blocks.
|
||||
|
||||
=item after_case NAME => sub { ... }
|
||||
|
||||
=item after_case NAME => \%params, sub { ... }
|
||||
|
||||
=item after_case($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Same as C<after_each> except it runs right after the case block, and before the
|
||||
test block.
|
||||
|
||||
These ARE NOT inherited by nested describe blocks.
|
||||
|
||||
=item after_all NAME => sub { ... }
|
||||
|
||||
=item after_all NAME => \%params, sub { ... }
|
||||
|
||||
=item after_all($NAME, \%PARAMS, \&CODE)
|
||||
|
||||
Same as C<before_all> except it runs after all test blocks have been run.
|
||||
|
||||
These ARE NOT inherited by nested describe blocks.
|
||||
|
||||
=back
|
||||
|
||||
=head2 SHORTCUTS
|
||||
|
||||
These are shortcuts. Each of these is the same as C<tests()> except some
|
||||
parameters are added for you.
|
||||
|
||||
These are NOT exported by default/.
|
||||
|
||||
=over 4
|
||||
|
||||
=item mini NAME => sub { ... }
|
||||
|
||||
Same as:
|
||||
|
||||
tests NAME => { flat => 1 }, sub { ... }
|
||||
|
||||
=item iso NAME => sub { ... }
|
||||
|
||||
Same as:
|
||||
|
||||
tests NAME => { iso => 1 }, sub { ... }
|
||||
|
||||
=item miso NAME => sub { ... }
|
||||
|
||||
Same as:
|
||||
|
||||
tests NAME => { mini => 1, iso => 1 }, sub { ... }
|
||||
|
||||
=item async NAME => sub { ... }
|
||||
|
||||
Same as:
|
||||
|
||||
tests NAME => { async => 1 }, sub { ... }
|
||||
|
||||
B<Note:> This conflicts with the C<async()> exported from L<threads>. Don't
|
||||
import both.
|
||||
|
||||
=item masync NAME => sub { ... }
|
||||
|
||||
Same as:
|
||||
|
||||
tests NAME => { minit => 1, async => 1 }, sub { ... }
|
||||
|
||||
=back
|
||||
|
||||
=head2 CUSTOM ATTRIBUTE DEFAULTS
|
||||
|
||||
Sometimes you want to apply default attributes to all C<tests()> or C<case()>
|
||||
blocks. This can be done, and is lexical to your describe or package root!
|
||||
|
||||
use Test2::Bundle::Extended;
|
||||
use Test2::Tools::Spec ':ALL';
|
||||
|
||||
# All 'tests' blocks after this declaration will have C<<iso => 1>> by default
|
||||
spec_defaults tests => (iso => 1);
|
||||
|
||||
tests foo => sub { ... }; # isolated
|
||||
|
||||
tests foo, {iso => 0}, sub { ... }; # Not isolated
|
||||
|
||||
spec_defaults tests => (iso => 0); # Turn it off again
|
||||
|
||||
Defaults are inherited by nested describe blocks. You can also override the
|
||||
defaults for the scope of the describe:
|
||||
|
||||
spec_defaults tests => (iso => 1);
|
||||
|
||||
describe foo => sub {
|
||||
spec_defaults tests => (async => 1); # Scoped to this describe and any child describes
|
||||
|
||||
tests bar => sub { ... }; # both iso and async
|
||||
};
|
||||
|
||||
tests baz => sub { ... }; # Just iso, no async.
|
||||
|
||||
You can apply defaults to any type of blocks:
|
||||
|
||||
spec_defaults case => (iso => 1); # All cases are 'iso';
|
||||
|
||||
Defaults are not inherited when a builder's return is captured.
|
||||
|
||||
spec_defaults tests => (iso => 1);
|
||||
|
||||
# Note we are not calling this in void context, that is the key here.
|
||||
my $d = describe foo => {
|
||||
tests bar => sub { ... }; # Not iso
|
||||
};
|
||||
|
||||
=head1 EXECUTION ORDER
|
||||
|
||||
As each function is encountered it executes, just like any other function. The
|
||||
C<describe()> function will immediately execute the codeblock it is given. All
|
||||
other functions will stash their codeblocks to be run later. When
|
||||
C<done_testing()> is run the workflow will be compiled, at which point all
|
||||
other blocks will run.
|
||||
|
||||
Here is an overview of the order in which blocks get called once compiled (at
|
||||
C<done_testing()>).
|
||||
|
||||
before_all
|
||||
for-each-case {
|
||||
before_case
|
||||
case
|
||||
after_case
|
||||
|
||||
# AND/OR nested describes
|
||||
before_each
|
||||
tests
|
||||
after_each
|
||||
}
|
||||
after_all
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Workflow can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist7@gmail.comE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
|
||||
172
database/perl/vendor/lib/Test2/Tools/Subtest.pm
vendored
Normal file
172
database/perl/vendor/lib/Test2/Tools/Subtest.pm
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
package Test2::Tools::Subtest;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Test2::API qw/context run_subtest/;
|
||||
use Test2::Util qw/try/;
|
||||
|
||||
our @EXPORT = qw/subtest_streamed subtest_buffered/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub subtest_streamed {
|
||||
my $name = shift;
|
||||
my $params = ref($_[0]) eq 'HASH' ? shift(@_) : {};
|
||||
my $code = shift;
|
||||
|
||||
$params->{buffered} = 0 unless defined $params->{buffered};
|
||||
|
||||
my $ctx = context();
|
||||
my $pass = run_subtest("Subtest: $name", $code, $params, @_);
|
||||
$ctx->release;
|
||||
return $pass;
|
||||
}
|
||||
|
||||
sub subtest_buffered {
|
||||
my $name = shift;
|
||||
my $params = ref($_[0]) eq 'HASH' ? shift(@_) : {};
|
||||
my $code = shift;
|
||||
|
||||
$params->{buffered} = 1 unless defined $params->{buffered};
|
||||
|
||||
my $ctx = context();
|
||||
my $pass = run_subtest($name, $code, $params, @_);
|
||||
$ctx->release;
|
||||
return $pass;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Subtest - Tools for writing subtests
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This package exports subs that let you write subtests.
|
||||
|
||||
There are two types of subtests, buffered and streamed. Streamed subtests mimic
|
||||
subtests from L<Test::More> in that they render all events as soon as they are
|
||||
produced. Buffered subtests wait until the subtest completes before rendering
|
||||
any results.
|
||||
|
||||
The main difference is that streamed subtests are unreadable when combined with
|
||||
concurrency. Buffered subtests look fine with any number of concurrent threads
|
||||
and processes.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
=head2 BUFFERED
|
||||
|
||||
use Test2::Tools::Subtest qw/subtest_buffered/;
|
||||
|
||||
subtest_buffered my_test => sub {
|
||||
ok(1, "subtest event A");
|
||||
ok(1, "subtest event B");
|
||||
};
|
||||
|
||||
This will produce output like this:
|
||||
|
||||
ok 1 - my_test {
|
||||
ok 1 - subtest event A
|
||||
ok 2 - subtest event B
|
||||
1..2
|
||||
}
|
||||
|
||||
=head2 STREAMED
|
||||
|
||||
The default option is 'buffered'. If you want streamed subtests,
|
||||
the way L<Test::Builder> does it, use this:
|
||||
|
||||
use Test2::Tools::Subtest qw/subtest_streamed/;
|
||||
|
||||
subtest_streamed my_test => sub {
|
||||
ok(1, "subtest event A");
|
||||
ok(1, "subtest event B");
|
||||
};
|
||||
|
||||
This will produce output like this:
|
||||
|
||||
# Subtest: my_test
|
||||
ok 1 - subtest event A
|
||||
ok 2 - subtest event B
|
||||
1..2
|
||||
ok 1 - Subtest: my_test
|
||||
|
||||
=head1 IMPORTANT NOTE
|
||||
|
||||
You can use C<bail_out> or C<skip_all> in a subtest, but not in a BEGIN block
|
||||
or C<use> statement. This is due to the way flow control works within a BEGIN
|
||||
block. This is not normally an issue, but can happen in rare conditions using
|
||||
eval, or script files as subtests.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item subtest_streamed $name => $sub
|
||||
|
||||
=item subtest_streamed($name, $sub, @args)
|
||||
|
||||
=item subtest_streamed $name => \%params, $sub
|
||||
|
||||
=item subtest_streamed($name, \%params, $sub, @args)
|
||||
|
||||
Run subtest coderef, stream events as they happen.
|
||||
|
||||
C<\%params> is a hashref with any arguments you wish to pass into hub
|
||||
construction.
|
||||
|
||||
=item subtest_buffered $name => $sub
|
||||
|
||||
=item subtest_buffered($name, $sub, @args)
|
||||
|
||||
=item subtest_buffered $name => \%params, $sub
|
||||
|
||||
=item subtest_buffered($name, \%params, $sub, @args)
|
||||
|
||||
Run subtest coderef, render events all at once when subtest is complete.
|
||||
|
||||
C<\%params> is a hashref with any arguments you wish to pass into hub
|
||||
construction.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
118
database/perl/vendor/lib/Test2/Tools/Target.pm
vendored
Normal file
118
database/perl/vendor/lib/Test2/Tools/Target.pm
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
package Test2::Tools::Target;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Carp qw/croak/;
|
||||
|
||||
use Test2::Util qw/pkg_to_file/;
|
||||
|
||||
sub import {
|
||||
my $class = shift;
|
||||
|
||||
my $caller = caller;
|
||||
$class->import_into($caller, @_);
|
||||
}
|
||||
|
||||
sub import_into {
|
||||
my $class = shift;
|
||||
my $into = shift or croak "no destination package provided";
|
||||
|
||||
croak "No targets specified" unless @_;
|
||||
|
||||
my %targets;
|
||||
if (@_ == 1) {
|
||||
if (ref $_[0] eq 'HASH') {
|
||||
%targets = %{ $_[0] };
|
||||
}
|
||||
else {
|
||||
($targets{CLASS}) = @_;
|
||||
}
|
||||
}
|
||||
else {
|
||||
%targets = @_;
|
||||
}
|
||||
|
||||
for my $name (keys %targets) {
|
||||
my $target = $targets{$name};
|
||||
|
||||
my $file = pkg_to_file($target);
|
||||
require $file;
|
||||
|
||||
$name ||= 'CLASS';
|
||||
|
||||
my $const;
|
||||
{
|
||||
my $const_target = "$target";
|
||||
$const = sub() { $const_target };
|
||||
}
|
||||
|
||||
no strict 'refs';
|
||||
*{"$into\::$name"} = \$target;
|
||||
*{"$into\::$name"} = $const;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Target - Alias the testing target package.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This lets you alias the package you are testing into a constant and a package
|
||||
variable.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Target 'Some::Package';
|
||||
|
||||
CLASS()->xxx; # Call 'xxx' on Some::Package
|
||||
$CLASS->xxx; # Same
|
||||
|
||||
Or you can specify names:
|
||||
|
||||
use Test2::Tools::Target pkg => 'Some::Package';
|
||||
|
||||
pkg()->xxx; # Call 'xxx' on Some::Package
|
||||
$pkg->xxx; # Same
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
257
database/perl/vendor/lib/Test2/Tools/Tester.pm
vendored
Normal file
257
database/perl/vendor/lib/Test2/Tools/Tester.pm
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
package Test2::Tools::Tester;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Carp qw/croak/;
|
||||
use Module::Pluggable search_path => ['Test2::EventFacet'], require => 1;
|
||||
use Test2::Util::Ref qw/rtype/;
|
||||
|
||||
use Importer Importer => 'import';
|
||||
|
||||
our @EXPORT_OK = qw{
|
||||
facets
|
||||
filter_events
|
||||
event_groups
|
||||
};
|
||||
|
||||
my %TYPES;
|
||||
for my $class (__PACKAGE__->plugins) {
|
||||
my $type = $class;
|
||||
$type =~ s/^Test2::EventFacet:://g;
|
||||
|
||||
next unless $class->isa('Test2::EventFacet');
|
||||
my $key;
|
||||
$key = $class->facet_key if $class->can('facet_key');
|
||||
$key = lc($type) unless defined $key;
|
||||
|
||||
$TYPES{$type} = $class;
|
||||
$TYPES{lc($type)} = $class;
|
||||
$TYPES{$key} = $class;
|
||||
}
|
||||
|
||||
sub filter_events {
|
||||
my $events = shift;
|
||||
|
||||
my @match = map { rtype($_) eq 'REGEXP' ? $_ : qr/^\Q$_\E::/} @_;
|
||||
|
||||
my @out;
|
||||
for my $e (@$events) {
|
||||
my $trace = $e->facet_data->{trace} or next;
|
||||
next unless grep { $trace->{frame}->[3] =~ $_ } @match;
|
||||
push @out => $e;
|
||||
}
|
||||
|
||||
return \@out;
|
||||
}
|
||||
|
||||
sub event_groups {
|
||||
my $events = shift;
|
||||
|
||||
my $out = {};
|
||||
for my $e (@$events) {
|
||||
my $trace = $e->facet_data->{trace};
|
||||
my $tool = ($trace && $trace->{frame} && $trace->{frame}->[3]) ? $trace->{frame}->[3] : undef;
|
||||
|
||||
unless ($tool) {
|
||||
push @{$out->{__NA__}} => $e;
|
||||
next;
|
||||
}
|
||||
|
||||
my ($pkg, $sub) = ($tool =~ m/^(.*)(?:::|')([^:']+)$/);
|
||||
|
||||
push @{$out->{$pkg}->{$sub}} => $e;
|
||||
push @{$out->{$pkg}->{__ALL__}} => $e;
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub facets {
|
||||
my ($type, $events) = @_;
|
||||
|
||||
my ($key, $is_list);
|
||||
my $class = $TYPES{$type};
|
||||
if ($class) {
|
||||
$key = $class->facet_key || lc($type);
|
||||
$is_list = $class->is_list;
|
||||
}
|
||||
else {
|
||||
$key = lc($type);
|
||||
}
|
||||
|
||||
my @out;
|
||||
for my $e (@$events) {
|
||||
my $fd = $e->facet_data;
|
||||
my $f = $fd->{$key} or next;
|
||||
|
||||
my $list = defined($is_list) ? $is_list : rtype($f) eq 'ARRAY';
|
||||
|
||||
if ($list) {
|
||||
push @out => map { $class ? $class->new($_) : $_ } @$f;
|
||||
}
|
||||
else {
|
||||
push @out => $class ? $class->new($f) : $f;
|
||||
}
|
||||
}
|
||||
|
||||
return \@out;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Tester - Tools to help you test other testing tools.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a collection of tools that are useful when testing other test tools.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Tester qw/event_groups filter_events facets/;
|
||||
|
||||
use Test2::Tools::Basic qw/plan pass ok/;
|
||||
use Test2::Tools::Compare qw/is like/;
|
||||
|
||||
my $events = intercept {
|
||||
plan 11;
|
||||
|
||||
pass('pass');
|
||||
ok(1, 'pass');
|
||||
|
||||
is(1, 1, "pass");
|
||||
like(1, 1, "pass");
|
||||
};
|
||||
|
||||
# Grab events generated by tools in Test2::Tools::Basic
|
||||
my $basic = filter $events => 'Test2::Tools::Basic';
|
||||
|
||||
# Grab events generated by Test2::Tools::Basic;
|
||||
my $compare = filter $events => 'Test2::Tools::Compare';
|
||||
|
||||
# Grab events generated by tools named 'ok'.
|
||||
my $oks = filter $events => qr/.*::ok$/;
|
||||
|
||||
my $grouped = group_events $events;
|
||||
# Breaks events into this structure:
|
||||
{
|
||||
'__NA__' => [ ... ],
|
||||
'Test2::Tools::Basic' => {
|
||||
'__ALL__' => [ $events->[0], $events->[1], $events->[2] ],
|
||||
plan => [ $events->[0] ],
|
||||
pass => [ $events->[1] ],
|
||||
ok => [ $events->[2] ],
|
||||
},
|
||||
Test2::Tools::Compare => { ... },
|
||||
}
|
||||
|
||||
# Get an arrayref of all the assert facets from the list of events.
|
||||
my $assert_facets = facets assert => $events;
|
||||
# [
|
||||
# bless({ details => 'pass', pass => 1}, 'Test2::EventFacet::Assert'),
|
||||
# bless({ details => 'pass', pass => 1}, 'Test2::EventFacet::Assert'),
|
||||
# ]
|
||||
|
||||
# Same, but for info facets
|
||||
my $info_facets = facets info => $events;
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
No subs are exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item $array_ref = filter $events => $PACKAGE
|
||||
|
||||
=item $array_ref = filter $events => $PACKAGE1, $PACKAGE2
|
||||
|
||||
=item $array_ref = filter $events => qr/match/
|
||||
|
||||
=item $array_ref = filter $events => qr/match/, $PACKAGE
|
||||
|
||||
This function takes an arrayref of events as the first argument. All additional
|
||||
arguments must either be a package name, or a regex. Any event that is
|
||||
generated by a tool in any of the package, or by a tool that matches any of the
|
||||
regexes, will be returned in an arrayref.
|
||||
|
||||
=item $grouped = group_events($events)
|
||||
|
||||
This function iterates all the events in the argument arrayref and splits them
|
||||
into groups. The resulting data structure is:
|
||||
|
||||
{ PACKAGE => { SUBNAME => [ $EVENT1, $EVENT2, ... }}
|
||||
|
||||
If the package of an event is not known it will be put into and arrayref under
|
||||
the '__NA__' key at the root of the structure. If a sub name is not known it
|
||||
will typically go under the '__ANON__' key in under the package name.
|
||||
|
||||
In addition there is an '__ALL__' key under each package which stores all of
|
||||
the events sorted into that group.
|
||||
|
||||
A more complete example:
|
||||
|
||||
{
|
||||
'__NA__' => [ $event->[3] ],
|
||||
'Test2::Tools::Basic' => {
|
||||
'__ALL__' => [ $events->[0], $events->[1], $events->[2] ],
|
||||
plan => [ $events->[0] ],
|
||||
pass => [ $events->[1] ],
|
||||
ok => [ $events->[2] ],
|
||||
},
|
||||
}
|
||||
|
||||
=item $arrayref = facets TYPE => $events
|
||||
|
||||
This function will compile a list of all facets of the specified type that are
|
||||
found in the arrayref of events. If the facet has a C<Test2::EventFacet::TYPE>
|
||||
package available then the facet will be constructed into an instance of the
|
||||
class, otherwise it is left as a hashref. Facet Order is preserved.
|
||||
|
||||
my $assert_facets = facets assert => $events;
|
||||
# [
|
||||
# bless({ details => 'pass', pass => 1}, 'Test2::EventFacet::Assert'),
|
||||
# bless({ details => 'pass', pass => 1}, 'Test2::EventFacet::Assert'),
|
||||
# ]
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
153
database/perl/vendor/lib/Test2/Tools/Warnings.pm
vendored
Normal file
153
database/perl/vendor/lib/Test2/Tools/Warnings.pm
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
package Test2::Tools::Warnings;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Test2::API qw/context/;
|
||||
|
||||
our @EXPORT = qw/warns warning warnings no_warnings/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub warns(&) {
|
||||
my $code = shift;
|
||||
my $warnings = 0;
|
||||
local $SIG{__WARN__} = sub { $warnings++ };
|
||||
$code->();
|
||||
return $warnings;
|
||||
}
|
||||
|
||||
sub no_warnings(&) { return !&warns(@_) }
|
||||
|
||||
sub warning(&) {
|
||||
my $code = shift;
|
||||
my @warnings;
|
||||
{
|
||||
local $SIG{__WARN__} = sub { push @warnings => @_ };
|
||||
$code->();
|
||||
return unless @warnings;
|
||||
}
|
||||
|
||||
if (@warnings > 1) {
|
||||
my $ctx = context();
|
||||
$ctx->alert("Extra warnings in warning { ... }");
|
||||
$ctx->note($_) for @warnings;
|
||||
$ctx->release;
|
||||
}
|
||||
|
||||
return $warnings[0];
|
||||
}
|
||||
|
||||
sub warnings(&) {
|
||||
my $code = shift;
|
||||
|
||||
my @warnings;
|
||||
local $SIG{__WARN__} = sub { push @warnings => @_ };
|
||||
$code->();
|
||||
|
||||
return \@warnings;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Tools::Warnings - Tools to verify warnings.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a collection of tools that can be used to test code that issues
|
||||
warnings.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Tools::Warnings qw/warns warning warnings no_warnings/;
|
||||
|
||||
ok(warns { warn 'a' }, "the code warns");
|
||||
ok(!warns { 1 }, "The code does not warn");
|
||||
is(warns { warn 'a'; warn 'b' }, 2, "got 2 warnings");
|
||||
|
||||
ok(no_warnings { ... }, "code did not warn");
|
||||
|
||||
like(
|
||||
warning { warn 'xxx' },
|
||||
qr/xxx/,
|
||||
"Got expected warning"
|
||||
);
|
||||
|
||||
is(
|
||||
warnings { warn "a\n"; warn "b\n" },
|
||||
[
|
||||
"a\n",
|
||||
"b\n",
|
||||
],
|
||||
"Got 2 specific warnings"
|
||||
);
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All subs are exported by default.
|
||||
|
||||
=over 4
|
||||
|
||||
=item $count = warns { ... }
|
||||
|
||||
Returns the count of warnings produced by the block. This will always return 0,
|
||||
or a positive integer.
|
||||
|
||||
=item $warning = warning { ... }
|
||||
|
||||
Returns the first warning generated by the block. If the block produces more
|
||||
than one warning, they will all be shown as notes, and an actual warning will tell
|
||||
you about it.
|
||||
|
||||
=item $warnings_ref = warnings { ... }
|
||||
|
||||
Returns an arrayref with all the warnings produced by the block. This will
|
||||
always return an array reference. If there are no warnings, this will return an
|
||||
empty array reference.
|
||||
|
||||
=item $bool = no_warnings { ... }
|
||||
|
||||
Return true if the block has no warnings. Returns false if there are warnings.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
The source code repository for Test2-Suite can be found at
|
||||
F<https://github.com/Test-More/Test2-Suite/>.
|
||||
|
||||
=head1 MAINTAINERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
|
||||
See F<http://dev.perl.org/licenses/>
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user