/usr/share/perl5/Test2/Workflow.pm is in libtest2-suite-perl 0.000102-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | package Test2::Workflow;
use strict;
use warnings;
our $VERSION = '0.000102';
our @EXPORT_OK = qw/parse_args current_build build root_build init_root build_stack/;
use base 'Exporter';
use Test2::Workflow::Build;
use Test2::Workflow::Task::Group;
use Test2::API qw/intercept/;
use Scalar::Util qw/blessed/;
sub parse_args {
my %input = @_;
my $args = delete $input{args};
my %out;
my %props;
my $caller = $out{frame} = $input{caller} || caller(defined $input{level} ? $input{level} : 1);
delete @input{qw/caller level/};
for my $arg (@$args) {
if (my $r = ref($arg)) {
if ($r eq 'HASH') {
%props = (%props, %$arg);
}
elsif ($r eq 'CODE') {
die "Code is already set, did you provide multiple code blocks at $caller->[1] line $caller->[2].\n"
if $out{code};
$out{code} = $arg
}
else {
die "Not sure what to do with $arg at $caller->[1] line $caller->[2].\n";
}
next;
}
if ($arg =~ m/^\d+$/) {
push @{$out{lines}} => $arg;
next;
}
die "Name is already set to '$out{name}', cannot set to '$arg', did you specify multiple names at $caller->[1] line $caller->[2].\n"
if $out{name};
$out{name} = $arg;
}
die "a name must be provided, and must be truthy at $caller->[1] line $caller->[2].\n"
unless $out{name};
die "a codeblock must be provided at $caller->[1] line $caller->[2].\n"
unless $out{code};
return { %props, %out, %input };
}
{
my %ROOT_BUILDS;
my @BUILD_STACK;
sub root_build { $ROOT_BUILDS{$_[0]} }
sub current_build { @BUILD_STACK ? $BUILD_STACK[-1] : undef }
sub build_stack { @BUILD_STACK }
sub init_root {
my ($pkg, %args) = @_;
$ROOT_BUILDS{$pkg} ||= Test2::Workflow::Build->new(
name => $pkg,
flat => 1,
iso => 0,
async => 0,
is_root => 1,
%args,
);
return $ROOT_BUILDS{$pkg};
}
sub build {
my %params = @_;
my $args = parse_args(%params);
my $build = Test2::Workflow::Build->new(%$args);
return $build if $args->{skip};
push @BUILD_STACK => $build;
my ($ok, $err);
my $events = intercept {
my $todo = $args->{todo} ? Test2::Todo->new(reason => $args->{todo}) : undef;
$ok = eval { $args->{code}->(); 1 };
$err = $@;
$todo->end if $todo;
};
# Clear the stash
$build->{stash} = [];
$build->set_events($events);
pop @BUILD_STACK;
unless($ok) {
my $hub = Test2::API::test2_stack->top;
my $count = @$events;
my $list = $count
? "Overview of unseen events:\n" . join "" => map " " . blessed($_) . " " . $_->trace->debug . "\n", @$events
: "";
die <<" EOT";
Exception in build '$args->{name}' with $count unseen event(s).
$err
$list
EOT
}
return $build;
}
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test2::Workflow - A test workflow is a way of structuring tests using
composable units.
=head1 DESCRIPTION
A test workflow is a way of structuring tests using composable units. A well
known example of a test workflow is L<RSPEC|http://rspec.info/>. RSPEC is
implemented using Test2::Workflow in L<Test2::Tools::Spec> along with several
extensions.
=head1 IMPORTANT CONCEPTS
=head2 BUILD
L<Test2::Workflow::Build>
A Build is used to compose tasks. Usually a build object is pushed to the stack
before running code that adds tasks to the build. Once the build sub is
complete the build is popped and returned. Usually a build is converted into a
root task or task group.
=head2 RUNNER
L<Test2::Workflow::Runner>
A runner takes the composed tasks and executes them in the proper order.
=head2 TASK
L<Test2::Workflow::Task>
A task is a unit of work to accomplish. There are 2 main types of task.
=head3 ACTION
An action is the most simple unit used in composition. An action is essentially
a name and a codeblock to run.
=head3 GROUP
A group is a task that is composed of other tasks.
=head1 EXPORTS
All exports are optional, you must request the ones you want.
=over 4
=item $parsed = parse_args(args => \@args)
=item $parsed = parse_args(args => \@args, level => $L)
=item $parsed = parse_args(args => \@args, caller => [caller($L)])
This will parse a "typical" task builders arguments. The C<@args> array MUST
contain a name (plain scalar containing text) and also a single CODE reference.
The C<@args> array MAY also contain any quantity of line numbers or hashrefs.
The resulting data structure will be a single hashref with all the provided
hashrefs squashed together, and the 'name', 'code', 'lines' and 'frame' keys
set from other arguments.
{
# All hashrefs from @args get squashed together:
%squashed_input_hashref_data,
# @args must have exactly 1 plaintext scalar that is not a number, it
# is considered the name:
name => 'name from input args'
# Integer values are treated as line numbers
lines => [ 35, 44 ],
# Exactly 1 coderef must be provided in @args:
code => \&some_code,
# 'frame' contains the 'caller' data. This may be passed in directly,
# obtained from the 'level' parameter, or automatically deduced.
frame => ['A::Package', 'a_file.pm', 42, ...],
}
=item $build = init_root($pkg, %args)
This will initialize (or return the existing) a build for the specified
package. C<%args> get passed into the L<Test2::Workflow::Build> constructor.
This uses the following defaults (which can be overridden using C<%args>):
name => $pkg,
flat => 1,
iso => 0,
async => 0,
is_root => 1,
Note that C<%args> is completely ignored if the package build has already been
initialized.
=item $build = root_build($pkg)
This will return the root build for the specified package.
=item $build = current_build()
This will return the build currently at the top of the build stack (or undef).
=item $build = build($name, \%params, sub { ... })
This will push a new build object onto the build stash then run the provided
codeblock. Once the codeblock has finished running the build will be popped off
the stack and returned.
See C<parse_args()> for details about argument processing.
=back
=head1 SEE ALSO
=over 4
=item Test2::Tools::Spec
L<Test2::Tools::Spec> is an implementation of RSPEC using this library.
=back
=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 2016 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
|