Initial Commit
This commit is contained in:
251
database/perl/vendor/lib/Test2/Util/Grabber.pm
vendored
Normal file
251
database/perl/vendor/lib/Test2/Util/Grabber.pm
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
package Test2::Util::Grabber;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Test2::Hub::Interceptor();
|
||||
use Test2::EventFacet::Trace();
|
||||
|
||||
use Test2::API qw/test2_stack test2_ipc/;
|
||||
|
||||
use Test2::Util::HashBase qw/hub finished _events term_size <state <trace/;
|
||||
|
||||
sub init {
|
||||
my $self = shift;
|
||||
|
||||
# Make sure we have a hub on the stack
|
||||
test2_stack->top();
|
||||
|
||||
my $hub = test2_stack->new_hub(
|
||||
class => 'Test2::Hub::Interceptor',
|
||||
formatter => undef,
|
||||
no_ending => 1,
|
||||
);
|
||||
|
||||
$self->{+HUB} = $hub;
|
||||
|
||||
my @events;
|
||||
$hub->listen(sub { push @events => $_[1] });
|
||||
|
||||
$self->{+_EVENTS} = \@events;
|
||||
|
||||
$self->{+TERM_SIZE} = $ENV{TS_TERM_SIZE};
|
||||
$ENV{TS_TERM_SIZE} = 80;
|
||||
|
||||
my $trace = $self->{+TRACE} ||= Test2::EventFacet::Trace->new(frame => [caller(1)]);
|
||||
my $state = $self->{+STATE} ||= {};
|
||||
$hub->clean_inherited(trace => $trace, state => $state);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub flush {
|
||||
my $self = shift;
|
||||
my $out = [@{$self->{+_EVENTS}}];
|
||||
@{$self->{+_EVENTS}} = ();
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub events {
|
||||
my $self = shift;
|
||||
# Copy
|
||||
return [@{$self->{+_EVENTS}}];
|
||||
}
|
||||
|
||||
sub finish {
|
||||
my ($self) = @_; # Do not shift;
|
||||
$_[0] = undef;
|
||||
|
||||
if (defined $self->{+TERM_SIZE}) {
|
||||
$ENV{TS_TERM_SIZE} = $self->{+TERM_SIZE};
|
||||
}
|
||||
else {
|
||||
delete $ENV{TS_TERM_SIZE};
|
||||
}
|
||||
|
||||
my $hub = $self->{+HUB};
|
||||
|
||||
$self->{+FINISHED} = 1;
|
||||
test2_stack()->pop($hub);
|
||||
|
||||
my $trace = $self->{+TRACE} ||= Test2::EventFacet::Trace->new(frame => [caller(1)]);
|
||||
my $state = $self->{+STATE} ||= {};
|
||||
$hub->clean_inherited(trace => $trace, state => $state);
|
||||
|
||||
my $dbg = Test2::EventFacet::Trace->new(
|
||||
frame => [caller(0)],
|
||||
);
|
||||
$hub->finalize($dbg, 1)
|
||||
if !$hub->no_ending
|
||||
&& !$hub->state->ended;
|
||||
|
||||
return $self->flush;
|
||||
}
|
||||
|
||||
sub DESTROY {
|
||||
my $self = shift;
|
||||
return if $self->{+FINISHED};
|
||||
test2_stack->pop($self->{+HUB});
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Util::Grabber - Object used to temporarily intercept all events.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Once created this object will intercept and stash all events sent to the shared
|
||||
L<Test2::Hub> object. Once the object is destroyed, events will once
|
||||
again be sent to the shared hub.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2 qw/Core 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");
|
||||
|
||||
# Same as flush, except it destroys the grab object.
|
||||
my $events_b = $grab->finish;
|
||||
|
||||
After calling C<finish()> the grab object is destroyed and C<$grab> is set to
|
||||
undef. C<$events_a> is an arrayref with the first two events. C<$events_b> is an
|
||||
arrayref with the second two events.
|
||||
|
||||
=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');
|
||||
|
||||
# $grab is magically undef after this.
|
||||
my $events = $grab->finish;
|
||||
|
||||
is(@$events, 2, "grabbed two events.");
|
||||
|
||||
When you call C<finish()> the C<$grab> object will automagically undef itself,
|
||||
but only for the reference used in the method call. If you have other
|
||||
references to the C<$grab> object they will not be set to undef.
|
||||
|
||||
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 one 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 METHODS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $grab = $class->new()
|
||||
|
||||
Create a new grab object, immediately starts intercepting events.
|
||||
|
||||
=item $ar = $grab->flush()
|
||||
|
||||
Get an arrayref of all the events so far, clearing the grab objects internal
|
||||
list.
|
||||
|
||||
=item $ar = $grab->events()
|
||||
|
||||
Get an arrayref of all events so far. Does not clear the internal list.
|
||||
|
||||
=item $ar = $grab->finish()
|
||||
|
||||
Get an arrayref of all the events, then destroy the grab object.
|
||||
|
||||
=item $hub = $grab->hub()
|
||||
|
||||
Get the hub that is used by the grab event.
|
||||
|
||||
=back
|
||||
|
||||
=head1 ENDING BEHAVIOR
|
||||
|
||||
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 one 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.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Test2::Tools::Intercept> - Accomplish the same thing, but using
|
||||
blocks instead.
|
||||
|
||||
=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
|
||||
118
database/perl/vendor/lib/Test2/Util/Ref.pm
vendored
Normal file
118
database/perl/vendor/lib/Test2/Util/Ref.pm
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
package Test2::Util::Ref;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Scalar::Util qw/reftype blessed refaddr/;
|
||||
|
||||
our @EXPORT_OK = qw/rtype render_ref/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub rtype {
|
||||
my ($thing) = @_;
|
||||
return '' unless defined $thing;
|
||||
|
||||
my $rf = ref $thing;
|
||||
my $rt = reftype $thing;
|
||||
|
||||
return '' unless $rf || $rt;
|
||||
return 'REGEXP' if $rf =~ m/Regex/i;
|
||||
return 'REGEXP' if $rt =~ m/Regex/i;
|
||||
return $rt || '';
|
||||
}
|
||||
|
||||
sub render_ref {
|
||||
my ($in) = @_;
|
||||
|
||||
return 'undef' unless defined($in);
|
||||
|
||||
my $type = rtype($in);
|
||||
return "$in" unless $type;
|
||||
|
||||
# Look past overloading
|
||||
my $class = blessed($in) || '';
|
||||
my $it = sprintf('0x%x', refaddr($in));
|
||||
my $ref = "$type($it)";
|
||||
|
||||
return $ref unless $class;
|
||||
return "$class=$ref";
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Util::Ref - Tools for inspecting or manipulating references.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
These are used by L<Test2::Tools> to inspect, render, or manipulate references.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All exports are optional. You must specify subs to import.
|
||||
|
||||
=over 4
|
||||
|
||||
=item $type = rtype($ref)
|
||||
|
||||
A normalization between C<Scalar::Util::reftype()> and C<ref()>.
|
||||
|
||||
Always returns a string.
|
||||
|
||||
Returns C<'REGEXP'> for regex types
|
||||
|
||||
Returns C<''> for non-refs
|
||||
|
||||
Otherwise returns what C<Scalar::Util::reftype()> returns.
|
||||
|
||||
=item $addr_str = render_ref($ref)
|
||||
|
||||
Always returns a string. For unblessed references this returns something like
|
||||
C<"SCALAR(0x...)">. For blessed references it returns
|
||||
C<"My::Thing=SCALAR(0x...)">. The only difference between this and C<$add_str =
|
||||
"$thing"> is that it ignores any overloading to ensure it is always the ref
|
||||
address.
|
||||
|
||||
=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>
|
||||
|
||||
=item Kent Fredric E<lt>kentnl@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
|
||||
247
database/perl/vendor/lib/Test2/Util/Stash.pm
vendored
Normal file
247
database/perl/vendor/lib/Test2/Util/Stash.pm
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
package Test2::Util::Stash;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Carp qw/croak/;
|
||||
use B;
|
||||
|
||||
our @EXPORT_OK = qw{
|
||||
get_stash
|
||||
get_glob
|
||||
get_symbol
|
||||
parse_symbol
|
||||
purge_symbol
|
||||
slot_to_sig sig_to_slot
|
||||
};
|
||||
use base 'Exporter';
|
||||
|
||||
my %SIGMAP = (
|
||||
'&' => 'CODE',
|
||||
'$' => 'SCALAR',
|
||||
'%' => 'HASH',
|
||||
'@' => 'ARRAY',
|
||||
);
|
||||
|
||||
my %SLOTMAP = reverse %SIGMAP;
|
||||
|
||||
sub slot_to_sig { $SLOTMAP{$_[0]} || croak "unsupported slot: '$_[0]'" }
|
||||
sub sig_to_slot { $SIGMAP{$_[0]} || croak "unsupported sigil: $_[0]" }
|
||||
|
||||
sub get_stash {
|
||||
my $package = shift || caller;
|
||||
no strict 'refs';
|
||||
return \%{"${package}\::"};
|
||||
}
|
||||
|
||||
sub get_glob {
|
||||
my $sym = _parse_symbol(scalar(caller), @_);
|
||||
no strict 'refs';
|
||||
no warnings 'once';
|
||||
return \*{"$sym->{package}\::$sym->{name}"};
|
||||
}
|
||||
|
||||
sub parse_symbol { _parse_symbol(scalar(caller), @_) }
|
||||
|
||||
sub _parse_symbol {
|
||||
my ($caller, $symbol, $package) = @_;
|
||||
|
||||
if (ref($symbol)) {
|
||||
my $pkg = $symbol->{package};
|
||||
|
||||
croak "Symbol package ($pkg) and package argument ($package) do not match"
|
||||
if $pkg && $package && $pkg ne $package;
|
||||
|
||||
$symbol->{package} ||= $caller;
|
||||
|
||||
return $symbol;
|
||||
}
|
||||
|
||||
utf8::downgrade($symbol) if $] == 5.010000; # prevent crash on 5.10.0
|
||||
my ($sig, $pkg, $name) = ($symbol =~ m/^(\W?)(.*::)?([^:]+)$/)
|
||||
or croak "Invalid symbol: '$symbol'";
|
||||
|
||||
# Normalize package, '::' becomes 'main', 'Foo::' becomes 'Foo'
|
||||
$pkg = $pkg
|
||||
? $pkg eq '::'
|
||||
? 'main'
|
||||
: substr($pkg, 0, -2)
|
||||
: undef;
|
||||
|
||||
croak "Symbol package ($pkg) and package argument ($package) do not match"
|
||||
if $pkg && $package && $pkg ne $package;
|
||||
|
||||
$sig ||= '&';
|
||||
my $type = $SIGMAP{$sig} || croak "unsupported sigil: '$sig'";
|
||||
|
||||
my $real_package = $package || $pkg || $caller;
|
||||
|
||||
return {
|
||||
name => $name,
|
||||
sigil => $sig,
|
||||
type => $type,
|
||||
symbol => "${sig}${real_package}::${name}",
|
||||
package => $real_package,
|
||||
};
|
||||
}
|
||||
|
||||
sub get_symbol {
|
||||
my $sym = _parse_symbol(scalar(caller), @_);
|
||||
|
||||
my $name = $sym->{name};
|
||||
my $type = $sym->{type};
|
||||
my $package = $sym->{package};
|
||||
my $symbol = $sym->{symbol};
|
||||
|
||||
my $stash = get_stash($package);
|
||||
return undef unless exists $stash->{$name};
|
||||
|
||||
my $glob = get_glob($sym);
|
||||
return *{$glob}{$type} if $type ne 'SCALAR' && defined(*{$glob}{$type});
|
||||
|
||||
if ($] < 5.010) {
|
||||
return undef unless defined(*{$glob}{$type});
|
||||
|
||||
{
|
||||
local ($@, $!);
|
||||
local $SIG{__WARN__} = sub { 1 };
|
||||
return *{$glob}{$type} if eval "package $package; my \$y = $symbol; 1";
|
||||
}
|
||||
|
||||
return undef unless defined *{$glob}{$type};
|
||||
return *{$glob}{$type} if defined ${*{$glob}{$type}};
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $sv = B::svref_2object($glob)->SV;
|
||||
return *{$glob}{$type} if $sv->isa('B::SV');
|
||||
return undef unless $sv->isa('B::SPECIAL');
|
||||
return *{$glob}{$type} if $B::specialsv_name[$$sv] ne 'Nullsv';
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub purge_symbol {
|
||||
my $sym = _parse_symbol(scalar(caller), @_);
|
||||
|
||||
local *GLOBCLONE = *{get_glob($sym)};
|
||||
delete get_stash($sym->{package})->{$sym->{name}};
|
||||
my $new_glob = get_glob($sym);
|
||||
|
||||
for my $type (qw/CODE SCALAR HASH ARRAY FORMAT IO/) {
|
||||
next if $type eq $sym->{type};
|
||||
my $ref = get_symbol({type => $type, name => 'GLOBCLONE', sigil => $SLOTMAP{$type}}, __PACKAGE__);
|
||||
next unless $ref;
|
||||
*$new_glob = $ref;
|
||||
}
|
||||
|
||||
return *GLOBCLONE{$sym->{type}};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Util::Stash - Utilities for manipulating stashes and globs.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a collection of utilities for manipulating and inspecting package
|
||||
stashes and globs.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item $stash = get_stash($package)
|
||||
|
||||
Gets the package stash. This is the same as C<$stash = \%Package::Name::>.
|
||||
|
||||
=item $sym_spec = parse_symbol($symbol)
|
||||
|
||||
=item $sym_spec = parse_symbol($symbol, $package)
|
||||
|
||||
Parse a symbol name, and return a hashref with info about the symbol.
|
||||
|
||||
C<$symbol> can be a simple name, or a fully qualified symbol name. The sigil is
|
||||
optional, and C<&> is assumed if none is provided. If C<$symbol> is fully qualified,
|
||||
and C<$package> is also provided, then the package of the symbol must match the
|
||||
C<$package>.
|
||||
|
||||
Returns a structure like this:
|
||||
|
||||
return {
|
||||
name => 'BAZ',
|
||||
sigil => '$',
|
||||
type => 'SCALAR',
|
||||
symbol => '&Foo::Bar::BAZ',
|
||||
package => 'Foo::Bar',
|
||||
};
|
||||
|
||||
=item $glob_ref = get_glob($symbol)
|
||||
|
||||
=item $glob_ref = get_glob($symbol, $package)
|
||||
|
||||
Get a glob ref. Arguments are the same as for C<parse_symbol>.
|
||||
|
||||
=item $ref = get_symbol($symbol)
|
||||
|
||||
=item $ref = get_symbol($symbol, $package)
|
||||
|
||||
Get a reference to the symbol. Arguments are the same as for C<parse_symbol>.
|
||||
|
||||
=item $ref = purge_symbol($symbol)
|
||||
|
||||
=item $ref = purge_symbol($symbol, $package)
|
||||
|
||||
Completely remove the symbol from the package symbol table. Arguments are the
|
||||
same as for C<parse_symbol>. A reference to the removed symbol is returned.
|
||||
|
||||
=item $sig = slot_to_sig($slot)
|
||||
|
||||
Convert a slot (like 'SCALAR') to a sigil (like '$').
|
||||
|
||||
=item $slot = sig_to_slot($sig)
|
||||
|
||||
Convert a sigil (like '$') to a slot (like 'SCALAR').
|
||||
|
||||
=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
|
||||
180
database/perl/vendor/lib/Test2/Util/Sub.pm
vendored
Normal file
180
database/perl/vendor/lib/Test2/Util/Sub.pm
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
package Test2::Util::Sub;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Carp qw/croak carp/;
|
||||
use B();
|
||||
use Sub::Info;
|
||||
|
||||
our @EXPORT_OK = qw{
|
||||
sub_info
|
||||
sub_name
|
||||
|
||||
gen_reader gen_writer gen_accessor
|
||||
};
|
||||
use base 'Exporter';
|
||||
|
||||
sub gen_reader {
|
||||
my $field = shift;
|
||||
return sub { $_[0]->{$field} };
|
||||
}
|
||||
|
||||
sub gen_writer {
|
||||
my $field = shift;
|
||||
return sub { $_[0]->{$field} = $_[1] };
|
||||
}
|
||||
|
||||
sub gen_accessor {
|
||||
my $field = shift;
|
||||
return sub {
|
||||
my $self = shift;
|
||||
($self->{$field}) = @_ if @_;
|
||||
return $self->{$field};
|
||||
};
|
||||
}
|
||||
|
||||
sub sub_name {
|
||||
my ($sub) = @_;
|
||||
|
||||
croak "sub_name requires a coderef as its only argument"
|
||||
unless ref($sub) eq 'CODE';
|
||||
|
||||
my $cobj = B::svref_2object($sub);
|
||||
my $name = $cobj->GV->NAME;
|
||||
return $name;
|
||||
}
|
||||
|
||||
sub sub_info {
|
||||
carp "Test2::Util::Sub::sub_info() is deprecated, use Sub::Info::sub_info() instead";
|
||||
Sub::Info::sub_info(@_);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Util::Sub - Tools for inspecting and manipulating subs.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Utilities used by Test2::Tools to inspect and manipulate subroutines.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All exports are optional, you must specify subs to import.
|
||||
|
||||
=over 4
|
||||
|
||||
=item $name = sub_name(\&sub)
|
||||
|
||||
Get the name of the sub.
|
||||
|
||||
=item my $hr = sub_info(\&code)
|
||||
|
||||
This returns a hashref with information about the sub:
|
||||
|
||||
{
|
||||
ref => \&code,
|
||||
cobj => $cobj,
|
||||
name => "Some::Mod::code",
|
||||
file => "Some/Mod.pm",
|
||||
package => "Some::Mod",
|
||||
|
||||
# Note: These have been adjusted based on guesswork.
|
||||
start_line => 22,
|
||||
end_line => 42,
|
||||
lines => [22, 42],
|
||||
|
||||
# Not a bug, these lines are different!
|
||||
all_lines => [23, 25, ..., 39, 41],
|
||||
};
|
||||
|
||||
=over 4
|
||||
|
||||
=item $info->{ref} => \&code
|
||||
|
||||
This is the original sub passed to C<sub_info()>.
|
||||
|
||||
=item $info->{cobj} => $cobj
|
||||
|
||||
This is the c-object representation of the coderef.
|
||||
|
||||
=item $info->{name} => "Some::Mod::code"
|
||||
|
||||
This is the name of the coderef. For anonymous coderefs this may end with
|
||||
C<'__ANON__'>. Also note that the package 'main' is special, and 'main::' may
|
||||
be omitted.
|
||||
|
||||
=item $info->{file} => "Some/Mod.pm"
|
||||
|
||||
The file in which the sub was defined.
|
||||
|
||||
=item $info->{package} => "Some::Mod"
|
||||
|
||||
The package in which the sub was defined.
|
||||
|
||||
=item $info->{start_line} => 22
|
||||
|
||||
=item $info->{end_line} => 42
|
||||
|
||||
=item $info->{lines} => [22, 42]
|
||||
|
||||
These three fields are the I<adjusted> start line, end line, and array with both.
|
||||
It is important to note that these lines have been adjusted and may not be
|
||||
accurate.
|
||||
|
||||
The lines are obtained by walking the ops. As such, the first line is the line
|
||||
of the first statement, and the last line is the line of the last statement.
|
||||
This means that in multi-line subs the lines are usually off by 1. The lines
|
||||
in these keys will be adjusted for you if it detects a multi-line sub.
|
||||
|
||||
=item $info->{all_lines} => [23, 25, ..., 39, 41]
|
||||
|
||||
This is an array with the lines of every statement in the sub. Unlike the other
|
||||
line fields, these have not been adjusted for you.
|
||||
|
||||
=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>
|
||||
|
||||
=item Kent Fredric E<lt>kentnl@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
|
||||
199
database/perl/vendor/lib/Test2/Util/Table.pm
vendored
Normal file
199
database/perl/vendor/lib/Test2/Util/Table.pm
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
package Test2::Util::Table;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use base 'Term::Table';
|
||||
|
||||
use Importer Importer => 'import';
|
||||
our @EXPORT_OK = qw/table/;
|
||||
our %EXPORT_GEN = (
|
||||
'&term_size' => sub {
|
||||
require Carp;
|
||||
Carp::cluck "term_size should be imported from Test2::Util::Term, not " . __PACKAGE__;
|
||||
Test2::Util::Term->can('term_size');
|
||||
},
|
||||
);
|
||||
|
||||
sub table {
|
||||
my %params = @_;
|
||||
|
||||
$params{collapse} ||= 0;
|
||||
$params{sanitize} ||= 0;
|
||||
$params{mark_tail} ||= 0;
|
||||
$params{show_header} ||= 0 unless $params{header} && @{$params{header}};
|
||||
|
||||
__PACKAGE__->new(%params)->render;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Util::Table - Format a header and rows into a table
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is used by some failing tests to provide diagnostics about what has gone
|
||||
wrong. This module is able to generic format rows of data into tables.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Util::Table qw/table/;
|
||||
|
||||
my @table = table(
|
||||
max_width => 80,
|
||||
collapse => 1, # Do not show empty columns
|
||||
header => [ 'name', 'age', 'hair color' ],
|
||||
rows => [
|
||||
[ 'Fred Flinstone', 2000000, 'black' ],
|
||||
[ 'Wilma Flinstone', 1999995, 'red' ],
|
||||
...,
|
||||
],
|
||||
);
|
||||
|
||||
# The @table array contains each line of the table, no newlines added.
|
||||
say $_ for @table;
|
||||
|
||||
This prints a table like this:
|
||||
|
||||
+-----------------+---------+------------+
|
||||
| name | age | hair color |
|
||||
+-----------------+---------+------------+
|
||||
| Fred Flinstone | 2000000 | black |
|
||||
| Wilma Flinstone | 1999995 | red |
|
||||
| ... | ... | ... |
|
||||
+-----------------+---------+------------+
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
=head2 @rows = table(...)
|
||||
|
||||
The function returns a list of lines, lines do not have the newline C<\n>
|
||||
character appended.
|
||||
|
||||
Options:
|
||||
|
||||
=over 4
|
||||
|
||||
=item header => [ ... ]
|
||||
|
||||
If you want a header specify it here. This takes an arrayref with each columns
|
||||
heading.
|
||||
|
||||
=item rows => [ [...], [...], ... ]
|
||||
|
||||
This should be an arrayref containing an arrayref per row.
|
||||
|
||||
=item collapse => $bool
|
||||
|
||||
Use this if you want to hide empty columns, that is any column that has no data
|
||||
in any row. Having a header for the column will not effect collapse.
|
||||
|
||||
=item max_width => $num
|
||||
|
||||
Set the maximum width of the table, the table may not be this big, but it will
|
||||
be no bigger. If none is specified it will attempt to find the width of your
|
||||
terminal and use that, otherwise it falls back to C<80>.
|
||||
|
||||
=item sanitize => $bool
|
||||
|
||||
This will sanitize all the data in the table such that newlines, control
|
||||
characters, and all whitespace except for ASCII 20 C<' '> are replaced with
|
||||
escape sequences. This prevents newlines, tabs, and similar whitespace from
|
||||
disrupting the table.
|
||||
|
||||
B<Note:> newlines are marked as '\n', but a newline is also inserted into the
|
||||
data so that it typically displays in a way that is useful to humans.
|
||||
|
||||
Example:
|
||||
|
||||
my $field = "foo\nbar\nbaz\n";
|
||||
|
||||
print join "\n" => table(
|
||||
sanitize => 1,
|
||||
rows => [
|
||||
[$field, 'col2' ],
|
||||
['row2 col1', 'row2 col2']
|
||||
]
|
||||
);
|
||||
|
||||
Prints:
|
||||
|
||||
+-----------------+-----------+
|
||||
| foo\n | col2 |
|
||||
| bar\n | |
|
||||
| baz\n | |
|
||||
| | |
|
||||
| row2 col1 | row2 col2 |
|
||||
+-----------------+-----------+
|
||||
|
||||
So it marks the newlines by inserting the escape sequence, but it also shows
|
||||
the data across as many lines as it would normally display.
|
||||
|
||||
=item mark_tail => $bool
|
||||
|
||||
This will replace the last whitespace character of any trailing whitespace with
|
||||
its escape sequence. This makes it easier to notice trailing whitespace when
|
||||
comparing values.
|
||||
|
||||
=back
|
||||
|
||||
=head2 my $cols = term_size()
|
||||
|
||||
Attempts to find the width in columns (characters) of the current terminal.
|
||||
Returns 80 as a safe bet if it cannot find it another way.
|
||||
|
||||
=head1 NOTE ON UNICODE/WIDE CHARACTERS
|
||||
|
||||
Some unicode characters, such as C<婧> (C<U+5A67>) are wider than others. These
|
||||
will render just fine if you C<use utf8;> as necessary, and
|
||||
L<Unicode::GCString> is installed, however if the module is not installed there
|
||||
will be anomalies in the table:
|
||||
|
||||
+-----+-----+---+
|
||||
| a | b | c |
|
||||
+-----+-----+---+
|
||||
| 婧 | x | y |
|
||||
| x | y | z |
|
||||
| x | 婧 | z |
|
||||
+-----+-----+---+
|
||||
|
||||
=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
|
||||
9
database/perl/vendor/lib/Test2/Util/Table/Cell.pm
vendored
Normal file
9
database/perl/vendor/lib/Test2/Util/Table/Cell.pm
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package Test2::Util::Table::Cell;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use base 'Term::Table::Cell';
|
||||
|
||||
1;
|
||||
67
database/perl/vendor/lib/Test2/Util/Table/LineBreak.pm
vendored
Normal file
67
database/perl/vendor/lib/Test2/Util/Table/LineBreak.pm
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package Test2::Util::Table::LineBreak;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use base 'Term::Table::LineBreak';
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Util::Table::LineBreak - Break up lines for use in tables.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is meant for internal use. This package takes long lines of text and
|
||||
splits them so that they fit in table rows.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Test2::Util::Table::LineBreak;
|
||||
|
||||
my $lb = Test2::Util::Table::LineBreak->new(string => $STRING);
|
||||
|
||||
$lb->break($SIZE);
|
||||
while (my $part = $lb->next) {
|
||||
...
|
||||
}
|
||||
|
||||
=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
|
||||
12
database/perl/vendor/lib/Test2/Util/Term.pm
vendored
Normal file
12
database/perl/vendor/lib/Test2/Util/Term.pm
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package Test2::Util::Term;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Term::Table::Util qw/term_size USE_GCS USE_TERM_READKEY uni_length/;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
use Importer Importer => 'import';
|
||||
our @EXPORT_OK = qw/term_size USE_GCS USE_TERM_READKEY uni_length/;
|
||||
|
||||
1;
|
||||
138
database/perl/vendor/lib/Test2/Util/Times.pm
vendored
Normal file
138
database/perl/vendor/lib/Test2/Util/Times.pm
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
package Test2::Util::Times;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use List::Util qw/sum/;
|
||||
|
||||
our $VERSION = '0.000139';
|
||||
|
||||
our @EXPORT_OK = qw/render_bench render_duration/;
|
||||
use base 'Exporter';
|
||||
|
||||
sub render_duration {
|
||||
my $time;
|
||||
if (@_ == 1) {
|
||||
($time) = @_;
|
||||
}
|
||||
else {
|
||||
my ($start, $end) = @_;
|
||||
$time = $end - $start;
|
||||
}
|
||||
|
||||
return sprintf('%1.5fs', $time) if $time < 10;
|
||||
return sprintf('%2.4fs', $time) if $time < 60;
|
||||
|
||||
my $msec = substr(sprintf('%0.2f', $time - int($time)), -2, 2);
|
||||
my $secs = $time % 60;
|
||||
my $mins = int($time / 60) % 60;
|
||||
my $hours = int($time / 60 / 60) % 24;
|
||||
my $days = int($time / 60 / 60 / 24);
|
||||
|
||||
my @units = (qw/d h m/, '');
|
||||
|
||||
my $duration = '';
|
||||
for my $t ($days, $hours, $mins, $secs) {
|
||||
my $u = shift @units;
|
||||
next unless $t || $duration;
|
||||
$duration = join ':' => grep { length($_) } $duration, sprintf('%02u%s', $t, $u);
|
||||
}
|
||||
|
||||
$duration ||= '0';
|
||||
$duration .= ".$msec" if int($msec);
|
||||
$duration .= 's';
|
||||
|
||||
return $duration;
|
||||
}
|
||||
|
||||
sub render_bench {
|
||||
my ($start, $end, $user, $system, $cuser, $csystem) = @_;
|
||||
|
||||
my $duration = render_duration($start, $end);
|
||||
|
||||
my $bench = sprintf(
|
||||
"%s on wallclock (%5.2f usr %5.2f sys + %5.2f cusr %5.2f csys = %5.2f CPU)",
|
||||
$duration, $user, $system, $cuser, $csystem, sum($user, $system, $cuser, $csystem),
|
||||
);
|
||||
$bench =~ s/\s+/ /g;
|
||||
$bench =~ s/(\(|\))\s+/$1/g;
|
||||
|
||||
return $bench;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Test2::Util::Times - Format timing/benchmark information.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This modules exports tools for rendering timing data at the end of tests.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
All exports are optional. You must specify subs to import.
|
||||
|
||||
=over 4
|
||||
|
||||
=item $str = render_bench($start, $end, $user, $system, $cuser, $csystem)
|
||||
|
||||
=item $str = render_bench($start, time(), times())
|
||||
|
||||
This will produce a string like one of these (Note these numbers are completely
|
||||
made up). I<Which string is used depends on the time elapsed.>
|
||||
|
||||
0.12345s on wallclock (0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.05 CPU)
|
||||
|
||||
11.1234s on wallclock (0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.05 CPU)
|
||||
|
||||
01m:54.45s on wallclock (0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.05 CPU)
|
||||
|
||||
18h:22m:54.45s on wallclock (0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.05 CPU)
|
||||
|
||||
04d:18h:22m:54.45s on wallclock (0.05 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.05 CPU)
|
||||
|
||||
The first 2 arguments are the C<$start> and C<$end> times in seconds (as
|
||||
returned by C<time()> or C<Time::HiRes::time()>).
|
||||
|
||||
The last 4 arguments are timing information as returned by the C<times()>
|
||||
function.
|
||||
|
||||
=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