1package Test2::Event; 2use strict; 3use warnings; 4 5our $VERSION = '1.302133'; 6 7use Scalar::Util qw/blessed reftype/; 8use Carp qw/croak/; 9 10use Test2::Util::HashBase qw/trace -amnesty uuid -hubs/; 11use Test2::Util::ExternalMeta qw/meta get_meta set_meta delete_meta/; 12use Test2::Util qw(pkg_to_file); 13 14use Test2::EventFacet::About(); 15use Test2::EventFacet::Amnesty(); 16use Test2::EventFacet::Assert(); 17use Test2::EventFacet::Control(); 18use Test2::EventFacet::Error(); 19use Test2::EventFacet::Info(); 20use Test2::EventFacet::Meta(); 21use Test2::EventFacet::Parent(); 22use Test2::EventFacet::Plan(); 23use Test2::EventFacet::Trace(); 24use Test2::EventFacet::Hub(); 25 26# Legacy tools will expect this to be loaded now 27require Test2::Util::Trace; 28 29my %LOADED_FACETS = ( 30 'about' => 'Test2::EventFacet::About', 31 'amnesty' => 'Test2::EventFacet::Amnesty', 32 'assert' => 'Test2::EventFacet::Assert', 33 'control' => 'Test2::EventFacet::Control', 34 'errors' => 'Test2::EventFacet::Error', 35 'info' => 'Test2::EventFacet::Info', 36 'meta' => 'Test2::EventFacet::Meta', 37 'parent' => 'Test2::EventFacet::Parent', 38 'plan' => 'Test2::EventFacet::Plan', 39 'trace' => 'Test2::EventFacet::Trace', 40 'hubs' => 'Test2::EventFacet::Hub', 41); 42 43sub FACET_TYPES { sort values %LOADED_FACETS } 44 45sub load_facet { 46 my $class = shift; 47 my ($facet) = @_; 48 49 return $LOADED_FACETS{$facet} if exists $LOADED_FACETS{$facet}; 50 51 my @check = ($facet); 52 if ('s' eq substr($facet, -1, 1)) { 53 push @check => substr($facet, 0, -1); 54 } 55 else { 56 push @check => $facet . 's'; 57 } 58 59 my $found; 60 for my $check (@check) { 61 my $mod = "Test2::EventFacet::" . ucfirst($facet); 62 my $file = pkg_to_file($mod); 63 next unless eval { require $file; 1 }; 64 $found = $mod; 65 last; 66 } 67 68 return undef unless $found; 69 $LOADED_FACETS{$facet} = $found; 70} 71 72sub causes_fail { 0 } 73sub increments_count { 0 } 74sub diagnostics { 0 } 75sub no_display { 0 } 76sub subtest_id { undef } 77 78sub callback { } 79 80sub terminate { () } 81sub global { () } 82sub sets_plan { () } 83 84sub summary { ref($_[0]) } 85 86sub related { 87 my $self = shift; 88 my ($event) = @_; 89 90 my $tracea = $self->trace or return undef; 91 my $traceb = $event->trace or return undef; 92 93 my $uuida = $tracea->uuid; 94 my $uuidb = $traceb->uuid; 95 if ($uuida && $uuidb) { 96 return 1 if $uuida eq $uuidb; 97 return 0; 98 } 99 100 my $siga = $tracea->signature or return undef; 101 my $sigb = $traceb->signature or return undef; 102 103 return 1 if $siga eq $sigb; 104 return 0; 105} 106 107sub add_hub { 108 my $self = shift; 109 unshift @{$self->{+HUBS}} => @_; 110} 111 112sub add_amnesty { 113 my $self = shift; 114 115 for my $am (@_) { 116 $am = {%$am} if ref($am) ne 'ARRAY'; 117 $am = Test2::EventFacet::Amnesty->new($am); 118 119 push @{$self->{+AMNESTY}} => $am; 120 } 121} 122 123sub common_facet_data { 124 my $self = shift; 125 126 my %out; 127 128 $out{about} = {package => ref($self) || undef}; 129 if (my $uuid = $self->uuid) { 130 $out{about}->{uuid} = $uuid; 131 } 132 133 if (my $trace = $self->trace) { 134 $out{trace} = { %$trace }; 135 } 136 137 if (my $hubs = $self->hubs) { 138 $out{hubs} = $hubs; 139 } 140 141 $out{amnesty} = [map {{ %{$_} }} @{$self->{+AMNESTY}}] 142 if $self->{+AMNESTY}; 143 144 if (my $meta = $self->meta_facet_data) { 145 $out{meta} = $meta; 146 } 147 148 return \%out; 149} 150 151sub meta_facet_data { 152 my $self = shift; 153 154 my $key = Test2::Util::ExternalMeta::META_KEY(); 155 156 my $hash = $self->{$key} or return undef; 157 return {%$hash}; 158} 159 160sub facet_data { 161 my $self = shift; 162 163 my $out = $self->common_facet_data; 164 165 $out->{about}->{details} = $self->summary || undef; 166 $out->{about}->{no_display} = $self->no_display || undef; 167 168 # Might be undef, we want to preserve that 169 my $terminate = $self->terminate; 170 $out->{control} = { 171 global => $self->global || 0, 172 terminate => $terminate, 173 has_callback => $self->can('callback') == \&callback ? 0 : 1, 174 }; 175 176 $out->{assert} = { 177 no_debug => 1, # Legacy behavior 178 pass => $self->causes_fail ? 0 : 1, 179 details => $self->summary, 180 } if $self->increments_count; 181 182 $out->{parent} = {hid => $self->subtest_id} if $self->subtest_id; 183 184 if (my @plan = $self->sets_plan) { 185 $out->{plan} = {}; 186 187 $out->{plan}->{count} = $plan[0] if defined $plan[0]; 188 $out->{plan}->{details} = $plan[2] if defined $plan[2]; 189 190 if ($plan[1]) { 191 $out->{plan}->{skip} = 1 if $plan[1] eq 'SKIP'; 192 $out->{plan}->{none} = 1 if $plan[1] eq 'NO PLAN'; 193 } 194 195 $out->{control}->{terminate} ||= 0 if $out->{plan}->{skip}; 196 } 197 198 if ($self->causes_fail && !$out->{assert}) { 199 $out->{errors} = [ 200 { 201 tag => 'FAIL', 202 fail => 1, 203 details => $self->summary, 204 } 205 ]; 206 } 207 208 my %IGNORE = (trace => 1, about => 1, control => 1); 209 my $do_info = !grep { !$IGNORE{$_} } keys %$out; 210 211 if ($do_info && !$self->no_display && $self->diagnostics) { 212 $out->{info} = [ 213 { 214 tag => 'DIAG', 215 debug => 1, 216 details => $self->summary, 217 } 218 ]; 219 } 220 221 return $out; 222} 223 224sub facets { 225 my $self = shift; 226 my %out; 227 228 my $data = $self->facet_data; 229 my @errors = $self->validate_facet_data($data); 230 die join "\n" => @errors if @errors; 231 232 for my $facet (keys %$data) { 233 my $class = $self->load_facet($facet); 234 my $val = $data->{$facet}; 235 236 unless($class) { 237 $out{$facet} = $val; 238 next; 239 } 240 241 my $is_list = reftype($val) eq 'ARRAY' ? 1 : 0; 242 if ($is_list) { 243 $out{$facet} = [map { $class->new($_) } @$val]; 244 } 245 else { 246 $out{$facet} = $class->new($val); 247 } 248 } 249 250 return \%out; 251} 252 253sub validate_facet_data { 254 my $class_or_self = shift; 255 my ($f, %params); 256 257 $f = shift if @_ && (reftype($_[0]) || '') eq 'HASH'; 258 %params = @_; 259 260 $f ||= $class_or_self->facet_data if blessed($class_or_self); 261 croak "No facet data" unless $f; 262 263 my @errors; 264 265 for my $k (sort keys %$f) { 266 my $fclass = $class_or_self->load_facet($k); 267 268 push @errors => "Could not find a facet class for facet '$k'" 269 if $params{require_facet_class} && !$fclass; 270 271 next unless $fclass; 272 273 my $v = $f->{$k}; 274 next unless defined($v); # undef is always fine 275 276 my $is_list = $fclass->is_list(); 277 my $got_list = reftype($v) eq 'ARRAY' ? 1 : 0; 278 279 push @errors => "Facet '$k' should be a list, but got a single item ($v)" 280 if $is_list && !$got_list; 281 282 push @errors => "Facet '$k' should not be a list, but got a a list ($v)" 283 if $got_list && !$is_list; 284 } 285 286 return @errors; 287} 288 289sub nested { 290 my $self = shift; 291 292 Carp::cluck("Use of Test2::Event->nested() is deprecated, use Test2::Event->trace->nested instead") 293 if $ENV{AUTHOR_TESTING}; 294 295 if (my $hubs = $self->{+HUBS}) { 296 return $hubs->[0]->{nested} if @$hubs; 297 } 298 299 my $trace = $self->{+TRACE} or return undef; 300 return $trace->{nested}; 301} 302 303sub in_subtest { 304 my $self = shift; 305 306 Carp::cluck("Use of Test2::Event->in_subtest() is deprecated, use Test2::Event->trace->hid instead") 307 if $ENV{AUTHOR_TESTING}; 308 309 my $hubs = $self->{+HUBS}; 310 if ($hubs && @$hubs) { 311 return undef unless $hubs->[0]->{nested}; 312 return $hubs->[0]->{hid} 313 } 314 315 my $trace = $self->{+TRACE} or return undef; 316 return undef unless $trace->{nested}; 317 return $trace->{hid}; 318} 319 3201; 321 322__END__ 323 324=pod 325 326=encoding UTF-8 327 328=head1 NAME 329 330Test2::Event - Base class for events 331 332=head1 DESCRIPTION 333 334Base class for all event objects that get passed through 335L<Test2>. 336 337=head1 SYNOPSIS 338 339 package Test2::Event::MyEvent; 340 use strict; 341 use warnings; 342 343 # This will make our class an event subclass (required) 344 use base 'Test2::Event'; 345 346 # Add some accessors (optional) 347 # You are not obligated to use HashBase, you can use any object tool you 348 # want, or roll your own accessors. 349 use Test2::Util::HashBase qw/foo bar baz/; 350 351 # Use this if you want the legacy API to be written for you, for this to 352 # work you will need to implement a facet_data() method. 353 use Test2::Util::Facets2Legacy; 354 355 # Chance to initialize some defaults 356 sub init { 357 my $self = shift; 358 # no other args in @_ 359 360 $self->set_foo('xxx') unless defined $self->foo; 361 362 ... 363 } 364 365 # This is the new way for events to convey data to the Test2 system 366 sub facet_data { 367 my $self = shift; 368 369 # Get common facets such as 'about', 'trace' 'amnesty', and 'meta' 370 my $facet_data = $self->common_facet_data(); 371 372 # Are you making an assertion? 373 $facet_data->{assert} = {pass => 1, details => 'my assertion'}; 374 ... 375 376 return $facet_data; 377 } 378 379 1; 380 381=head1 METHODS 382 383=head2 GENERAL 384 385=over 4 386 387=item $trace = $e->trace 388 389Get a snapshot of the L<Test2::EventFacet::Trace> as it was when this event was 390generated 391 392=item $bool_or_undef = $e->related($e2) 393 394Check if 2 events are related. In this case related means their traces share a 395signature meaning they were created with the same context (or at the very least 396by contexts which share an id, which is the same thing unless someone is doing 397something very bad). 398 399This can be used to reliably link multiple events created by the same tool. For 400instance a failing test like C<ok(0, "fail"> will generate 2 events, one being 401a L<Test2::Event::Ok>, the other being a L<Test2::Event::Diag>, both of these 402events are related having been created under the same context and by the same 403initial tool (though multiple tools may have been nested under the initial 404one). 405 406This will return C<undef> if the relationship cannot be checked, which happens 407if either event has an incomplete or missing trace. This will return C<0> if 408the traces are complete, but do not match. C<1> will be returned if there is a 409match. 410 411=item $e->add_amnesty({tag => $TAG, details => $DETAILS}); 412 413This can be used to add amnesty to this event. Amnesty only effects failing 414assertions in most cases, but some formatters may display them for passing 415assertions, or even non-assertions as well. 416 417Amnesty will prevent a failed assertion from causing the overall test to fail. 418In other words it marks a failure as expected and allowed. 419 420B<Note:> This is how 'TODO' is implemented under the hood. TODO is essentially 421amnesty with the 'TODO' tag. The details are the reason for the TODO. 422 423=item $uuid = $e->uuid 424 425If UUID tagging is enabled (See L<Test::API>) then any event that has made its 426way through a hub will be tagged with a UUID. A newly created event will not 427yet be tagged in most cases. 428 429=item $class = $e->load_facet($name) 430 431This method is used to load a facet by name (or key). It will attempt to load 432the facet class, if it succeeds it will return the class it loaded. If it fails 433it will return C<undef>. This caches the result at the class level so that 434future calls will be faster. 435 436The C<$name> variable should be the key used to access the facet in a facets 437hashref. For instance the assertion facet has the key 'assert', the information 438facet has the 'info' key, and the error facet has the key 'errors'. You may 439include or omit the 's' at the end of the name, the method is smart enough to 440try both the 's' and no-'s' forms, it will check what you provided first, and 441if that is not found it will add or strip the 's and try again. 442 443=item @classes = $e->FACET_TYPES() 444 445=item @classes = Test2::Event->FACET_TYPES() 446 447This returns a list of all facets that have been loaded using the 448C<load_facet()> method. This will not return any classes that have not been 449loaded, or have been loaded directly without a call to C<load_facet()>. 450 451B<Note:> The core facet types are automatically loaded and populated in this 452list. 453 454=back 455 456=head2 NEW API 457 458=over 4 459 460=item $hashref = $e->common_facet_data(); 461 462This can be used by subclasses to generate a starting facet data hashref. This 463will populate the hashref with the trace, meta, amnesty, and about facets. 464These facets are nearly always produced the same way for all events. 465 466=item $hashref = $e->facet_data() 467 468If you do not override this then the default implementation will attempt to 469generate facets from the legacy API. This generation is limited only to what 470the legacy API can provide. It is recommended that you override this method and 471write out explicit facet data. 472 473=item $hashref = $e->facets() 474 475This takes the hashref from C<facet_data()> and blesses each facet into the 476proper C<Test2::EventFacet::*> subclass. If no class can be found for any given 477facet it will be passed along unchanged. 478 479=item @errors = $e->validate_facet_data(); 480 481=item @errors = $e->validate_facet_data(%params); 482 483=item @errors = $e->validate_facet_data(\%facets, %params); 484 485=item @errors = Test2::Event->validate_facet_data(%params); 486 487=item @errors = Test2::Event->validate_facet_data(\%facets, %params); 488 489This method will validate facet data and return a list of errors. If no errors 490are found this will return an empty list. 491 492This can be called as an object method with no arguments, in which case the 493C<facet_data()> method will be called to get the facet data to be validated. 494 495When used as an object method the C<\%facet_data> argument may be omitted. 496 497When used as a class method the C<\%facet_data> argument is required. 498 499Remaining arguments will be slurped into a C<%params> hash. 500 501Currently only 1 parameter is defined: 502 503=over 4 504 505=item require_facet_class => $BOOL 506 507When set to true (default is false) this will reject any facets where a facet 508class cannot be found. Normally facets without classes are assumed to be custom 509and are ignored. 510 511=back 512 513=back 514 515=head3 WHAT ARE FACETS? 516 517Facets are how events convey their purpose to the Test2 internals and 518formatters. An event without facets will have no intentional effect on the 519overall test state, and will not be displayed at all by most formatters, except 520perhaps to say that an event of an unknown type was seen. 521 522Facets are produced by the C<facet_data()> subroutine, which you should 523nearly-always override. C<facet_data()> is expected to return a hashref where 524each key is the facet type, and the value is either a hashref with the data for 525that facet, or an array of hashref's. Some facets must be defined as single 526hashrefs, some must be defined as an array of hashrefs, No facets allow both. 527 528C<facet_data()> B<MUST NOT> bless the data it returns, the main hashref, and 529nested facet hashref's B<MUST> be bare, though items contained within each 530facet may be blessed. The data returned by this method B<should> also be copies 531of the internal data in order to prevent accidental state modification. 532 533C<facets()> takes the data from C<facet_data()> and blesses it into the 534C<Test2::EventFacet::*> packages. This is rarely used however, the EventFacet 535packages are primarily for convenience and documentation. The EventFacet 536classes are not used at all internally, instead the raw data is used. 537 538Here is a list of facet types by package. The packages are not used internally, 539but are where the documentation for each type is kept. 540 541B<Note:> Every single facet type has the C<'details'> field. This field is 542always intended for human consumption, and when provided, should explain the 543'why' for the facet. All other fields are facet specific. 544 545=over 4 546 547=item about => {...} 548 549L<Test2::EventFacet::About> 550 551This contains information about the event itself such as the event package 552name. The C<details> field for this facet is an overall summary of the event. 553 554=item assert => {...} 555 556L<Test2::EventFacet::Assert> 557 558This facet is used if an assertion was made. The C<details> field of this facet 559is the description of the assertion. 560 561=item control => {...} 562 563L<Test2::EventFacet::Control> 564 565This facet is used to tell the L<Test2::Event::Hub> about special actions the 566event causes. Things like halting all testing, terminating the current test, 567etc. In this facet the C<details> field explains why any special action was 568taken. 569 570B<Note:> This is how bail-out is implemented. 571 572=item meta => {...} 573 574L<Test2::EventFacet::Meta> 575 576The meta facet contains all the meta-data attached to the event. In this case 577the C<details> field has no special meaning, but may be present if something 578sets the 'details' meta-key on the event. 579 580=item parent => {...} 581 582L<Test2::EventFacet::Parent> 583 584This facet contains nested events and similar details for subtests. In this 585facet the C<details> field will typically be the name of the subtest. 586 587=item plan => {...} 588 589L<Test2::EventFacet::Plan> 590 591This facet tells the system that a plan has been set. The C<details> field of 592this is usually left empty, but when present explains why the plan is what it 593is, this is most useful if the plan is to skip-all. 594 595=item trace => {...} 596 597L<Test2::EventFacet::Trace> 598 599This facet contains information related to when and where the event was 600generated. This is how the test file and line number of a failure is known. 601This facet can also help you to tell if tests are related. 602 603In this facet the C<details> field overrides the "failed at test_file.t line 60442." message provided on assertion failure. 605 606=item amnesty => [{...}, ...] 607 608L<Test2::EventFacet::Amnesty> 609 610The amnesty facet is a list instead of a single item, this is important as 611amnesty can come from multiple places at once. 612 613For each instance of amnesty the C<details> field explains why amnesty was 614granted. 615 616B<Note:> Outside of formatters amnesty only acts to forgive a failing 617assertion. 618 619=item errors => [{...}, ...] 620 621L<Test2::EventFacet::Error> 622 623The errors facet is a list instead of a single item, any number of errors can 624be listed. In this facet C<details> describes the error, or may contain the raw 625error message itself (such as an exception). In perl exception may be blessed 626objects, as such the raw data for this facet may contain nested items which are 627blessed. 628 629Not all errors are considered fatal, there is a C<fail> field that must be set 630for an error to cause the test to fail. 631 632B<Note:> This facet is unique in that the field name is 'errors' while the 633package is 'Error'. This is because this is the only facet type that is both a 634list, and has a name where the plural is not the same as the singular. This may 635cause some confusion, but I feel it will be less confusing than the 636alternative. 637 638=item info => [{...}, ...] 639 640L<Test2::EventFacet::Info> 641 642The 'info' facet is a list instead of a single item, any quantity of extra 643information can be attached to an event. Some information may be critical 644diagnostics, others may be simply commentary in nature, this is determined by 645the C<debug> flag. 646 647For this facet the C<details> flag is the info itself. This info may be a 648string, or it may be a data structure to display. This is one of the few facet 649types that may contain blessed items. 650 651=back 652 653=head2 LEGACY API 654 655=over 4 656 657=item $bool = $e->causes_fail 658 659Returns true if this event should result in a test failure. In general this 660should be false. 661 662=item $bool = $e->increments_count 663 664Should be true if this event should result in a test count increment. 665 666=item $e->callback($hub) 667 668If your event needs to have extra effects on the L<Test2::Hub> you can override 669this method. 670 671This is called B<BEFORE> your event is passed to the formatter. 672 673=item $num = $e->nested 674 675If this event is nested inside of other events, this should be the depth of 676nesting. (This is mainly for subtests) 677 678=item $bool = $e->global 679 680Set this to true if your event is global, that is ALL threads and processes 681should see it no matter when or where it is generated. This is not a common 682thing to want, it is used by bail-out and skip_all to end testing. 683 684=item $code = $e->terminate 685 686This is called B<AFTER> your event has been passed to the formatter. This 687should normally return undef, only change this if your event should cause the 688test to exit immediately. 689 690If you want this event to cause the test to exit you should return the exit 691code here. Exit code of 0 means exit success, any other integer means exit with 692failure. 693 694This is used by L<Test2::Event::Plan> to exit 0 when the plan is 695'skip_all'. This is also used by L<Test2::Event:Bail> to force the test 696to exit with a failure. 697 698This is called after the event has been sent to the formatter in order to 699ensure the event is seen and understood. 700 701=item $msg = $e->summary 702 703This is intended to be a human readable summary of the event. This should 704ideally only be one line long, but you can use multiple lines if necessary. This 705is intended for human consumption. You do not need to make it easy for machines 706to understand. 707 708The default is to simply return the event package name. 709 710=item ($count, $directive, $reason) = $e->sets_plan() 711 712Check if this event sets the testing plan. It will return an empty list if it 713does not. If it does set the plan it will return a list of 1 to 3 items in 714order: Expected Test Count, Test Directive, Reason for directive. 715 716=item $bool = $e->diagnostics 717 718True if the event contains diagnostics info. This is useful because a 719non-verbose harness may choose to hide events that are not in this category. 720Some formatters may choose to send these to STDERR instead of STDOUT to ensure 721they are seen. 722 723=item $bool = $e->no_display 724 725False by default. This will return true on events that should not be displayed 726by formatters. 727 728=item $id = $e->in_subtest 729 730If the event is inside a subtest this should have the subtest ID. 731 732=item $id = $e->subtest_id 733 734If the event is a final subtest event, this should contain the subtest ID. 735 736=back 737 738=head1 THIRD PARTY META-DATA 739 740This object consumes L<Test2::Util::ExternalMeta> which provides a consistent 741way for you to attach meta-data to instances of this class. This is useful for 742tools, plugins, and other extensions. 743 744=head1 SOURCE 745 746The source code repository for Test2 can be found at 747F<http://github.com/Test-More/test-more/>. 748 749=head1 MAINTAINERS 750 751=over 4 752 753=item Chad Granum E<lt>exodist@cpan.orgE<gt> 754 755=back 756 757=head1 AUTHORS 758 759=over 4 760 761=item Chad Granum E<lt>exodist@cpan.orgE<gt> 762 763=back 764 765=head1 COPYRIGHT 766 767Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>. 768 769This program is free software; you can redistribute it and/or 770modify it under the same terms as Perl itself. 771 772See F<http://dev.perl.org/licenses/> 773 774=cut 775