Test2::Event(3perl)

πŸ’– Test2::Event πŸ’–

okay so bestie, welcome to Test2::Event, which is the manual page for Test2::Event (the Perl Programmers Reference Guide version, if we're being precise). this is part 1 of 2, so like. buckle up.


✨ NAME ✨

Test2::Event β€” the base class for events πŸ’…


🌸 DESCRIPTION 🌸

so like. it's the base class. for ALL the event objects that get passed through Test2. every single one. it's giving mother of all events, no cap. πŸ‘‘


πŸŽ€ SYNOPSIS πŸŽ€

here's the vibe, bestie β€” this is exactly how you'd write it:

package Test2::Event::MyEvent;
use strict;
use warnings;

# This will make our class an event subclass (required)
use base 'Test2::Event';

# Add some accessors (optional)
# You are not obligated to use HashBase, you can use any object tool you
# want, or roll your own accessors.
use Test2::Util::HashBase qw/foo bar baz/;

# Use this if you want the legacy API to be written for you, for this to
# work you will need to implement a facet_data() method.
use Test2::Util::Facets2Legacy;

# Chance to initialize some defaults
sub init {
    my $self = shift;
    # no other args in @_

    $self->set_foo('xxx') unless defined $self->foo;

    ...
}

# This is the new way for events to convey data to the Test2 system
sub facet_data {
    my $self = shift;

    # Get common facets such as 'about', 'trace' 'amnesty', and 'meta'
    my $facet_data = $self->common_facet_data();

    # Are you making an assertion?
    $facet_data->{assert} = {pass => 1, details => 'my assertion'};
    ...

    return $facet_data;
}

1;

πŸ’œ METHODS πŸ’œ

🌈 GENERAL 🌈

  • $trace = $e->trace β€” grabs you a snapshot of the Test2::EventFacet::Trace as it was back when this event was generated. like a little time capsule fr fr πŸ¦‹
  • $bool_or_undef = $e->related($e2) β€” checks if two events are related. and "related" here means their traces share a signature, meaning they were created with the same context (or, at the very least, by contexts that share an id β€” which is literally the same thing unless someone is out there doing something very bad πŸ™ˆ).

this is the move for reliably linking multiple events that the same tool made. like for instance, a failing test like "ok(0, "fail"" will generate 2 events β€” one being a Test2::Event::Ok, the other being a Test2::Event::Diag β€” and both of those are related, having been created under the same context and by the same initial tool (though multiple tools may have been nested under the initial one).

this returns undef if the relationship can't be checked, which happens if either event has an incomplete or missing trace. it returns 0 if the traces are complete but do not match. and 1 gets returned if there's a match. slay. βœ…

  • $e->add_amnesty({tag => $TAG, details => $DETAILS}); β€” use this to add amnesty to this event. amnesty only affects failing assertions in most cases, but some formatters may display them for passing assertions, or even non-assertions as well πŸ‘€.

amnesty will prevent a failed assertion from causing the overall test to fail. in other words, it marks a failure as expected and allowed. so generous of it πŸ’–

Note: this is how 'TODO' is implemented under the hood. TODO is essentially amnesty with the 'TODO' tag. the details are the reason for the TODO.
  • $uuid = $e->uuid β€” if UUID tagging is enabled (see Test::API) then any event that has made its way through a hub will be tagged with a UUID. a newly created event will not yet be tagged in most cases. brand new, no tag yet, iconic πŸŽ€
  • $class = $e->load_facet($name) β€” this method loads a facet by name (or key). it will attempt to load the facet class, and if it succeeds it returns the class it loaded. if it fails it returns undef. and it caches the result at the class level so that future calls are faster. efficiency queen 🧚

the $name variable should be the key used to access the facet in a facets hashref. for instance, the assertion facet has the key 'assert', the information facet has the 'info' key, and the error facet has the key 'errors'. you may include or omit the 's' at the end of the name β€” the method is smart enough to try both the 's' and no-'s' forms, checking what you provided first, and if that's not found it will add or strip the 's' and try again. so forgiving of it πŸ’…

  • @classes = $e->FACET_TYPES()
  • @classes = Test2::Event->FACET_TYPES() β€” returns a list of ALL facets that have been loaded using the load_facet() method. it will not return any classes that have not been loaded, or that have been loaded directly without a call to load_facet().
Note: the core facet types are automatically loaded and populated in this list. so those ones are just there, no extra work πŸ’

πŸ”₯ NEW API πŸ”₯

  • $hashref = $e->common_facet_data(); β€” subclasses can use this to generate a starting facet data hashref. it populates the hashref with the trace, meta, amnesty, and about facets. these facets are nearly always produced the same way for all events, so like. free real estate ✨
  • $hashref = $e->facet_data() β€” if you do not override this, the default implementation will attempt to generate facets from the legacy API. that generation is limited only to what the legacy API can provide. it is recommended that you override this method and write out explicit facet data. do it properly bestie, your future self says thank you 🫢
  • $hashref = $e->facets() β€” takes the hashref from facet_data() and blesses each facet into the proper "Test2::EventFacet::*" subclass. if no class can be found for any given facet, it will be passed along unchanged. no class? no problem, moving on πŸ’«
  • @errors = $e->validate_facet_data();
  • @errors = $e->validate_facet_data(%params);
  • @errors = $e->validate_facet_data(\%facets, %params);
  • @errors = Test2::Event->validate_facet_data(%params);
  • @errors = Test2::Event->validate_facet_data(\%facets, %params);

this method validates facet data and returns a list of errors. if no errors are found it returns an empty list. a clean bill of health, periodt βœ…

you can call it as an object method with no arguments, in which case the facet_data() method gets called to get the facet data that's gonna be validated.

when used as an object method, the \%facet_data argument may be omitted.

when used as a class method, the \%facet_data argument is required. no skipping it.

the remaining arguments get slurped into a %params hash.

currently only 1 parameter is defined:

  • require_facet_class => $BOOL β€” when set to true (default is false) this will reject any facets where a facet class cannot be found. normally, facets without classes are assumed to be custom and are ignored. so flip it to true if you're feeling strict πŸ’…

πŸ¦‹ WHAT ARE FACETS? πŸ¦‹

facets are how events convey their purpose to the Test2 internals and formatters. an event without facets will have no intentional effect on the overall test state, and will not be displayed at all by most formatters β€” except perhaps to say that an event of an unknown type was seen. so like, a ghost event. spooky πŸ‘»

facets are produced by the facet_data() subroutine, which you should nearly-always override. facet_data() is expected to return a hashref where each key is the facet type, and the value is either a hashref with the data for that facet, or an array of hashrefs. some facets must be defined as single hashrefs, some must be defined as an array of hashrefs β€” and no facets allow both. pick a lane babe πŸŽ€

facet_data() MUST NOT bless the data it returns β€” the main hashref and nested facet hashrefs MUST be bare, though items contained within each facet may be blessed. the data returned by this method should also be copies of the internal data, in order to prevent accidental state modification. protect the state, protect the vibe πŸ›‘οΈ

facets() takes the data from facet_data() and blesses it into the "Test2::EventFacet::*" packages. this is rarely used though β€” the EventFacet packages are primarily for convenience and documentation. the EventFacet classes are not used at all internally; instead, the raw data is used. so the classes are basically the aesthetic, and the raw data is the actual machinery 😌

here's a list of facet types by package. the packages are not used internally, but they're where the documentation for each type lives.

Note: every single facet type has the 'details' field. this field is always intended for human consumption, and when provided, should explain the 'why' for the facet. all other fields are facet specific.

about => {...}

Test2::EventFacet::About

this contains information about the event itself, like the event package name. the "details" field for this facet is an overall summary of the event. the tl;dr of the event, if you will ✨

assert => {...}

Test2::EventFacet::Assert

this facet is used if an assertion was made. the "details" field of this facet is the description of the assertion. so like, what you're claiming πŸ‘‘

control => {...}

Test2::EventFacet::Control

this facet tells the Test2::Hub about special actions the event causes. things like halting all testing, terminating the current test, etc. in this facet the "details" field explains why any special action was taken.

Note: this is how bail-out is implemented. 🚨

meta => {...}

Test2::EventFacet::Meta

the meta facet contains all the meta-data attached to the event. in this case the "details" field has no special meaning, but may be present if something sets the 'details' meta-key on the event. it's just vibes in there πŸ’«

parent => {...}

Test2::EventFacet::Parent

this facet contains nested events and similar details for subtests. in this facet the "details" field will typically be the name of the subtest. nesting doll energy πŸͺ†

plan => {...}

Test2::EventFacet::Plan

this facet tells the system that a plan has been set. the "details" field of this is usually left empty, but when present it explains why the plan is what it is β€” which is most useful if the plan is to skip-all. πŸ“‹

trace => {...}

Test2::EventFacet::Trace

this facet contains information related to when and where the event was generated. this is how the test file and line number of a failure is known. this facet can also help you tell if tests are related. the receipts πŸ“

in this facet, the "details" field overrides the "failed at test_file.t line 42." message provided on assertion failure.

amnesty => [{...}, ...]

Test2::EventFacet::Amnesty

the amnesty facet is a list instead of a single item β€” this is important, because amnesty can come from multiple places at once. multitasking forgiveness 🫢

for each instance of amnesty, the "details" field explains why amnesty was granted.

Note: outside of formatters, amnesty only acts to forgive a failing assertion.

errors => [{...}, ...]

Test2::EventFacet::Error

the errors facet is a list instead of a single item β€” any number of errors can be listed. in this facet, "details" describes the error, or may contain the raw error message itself (such as an exception). in perl, exceptions may be blessed objects, and as such the raw data for this facet may contain nested items which are blessed. messy? sure. but we love her πŸ’€


okay bestie, that's part 1, and there's more coming β€” don't go anywhere πŸ’–

...and honestly bestie, not every error is a fatal error. There's a fail field in there, and it has to be set for an error to actually make the test fail. No fail field, no failure. Simple as. πŸ’…

✨ Note: this facet is the ✨special one✨ β€” the field is called errors but the package is called Error. Why the mismatch? Because this is literally the only facet type that is both a list and has a name where the plural isn't just the singular again. Yeah it looks a lil cursed, but the author promises it's less confusing than the alternative. Trust. 🫢

πŸ¦‹ info => [{...}, ...]

Test2::EventFacet::Info

The info facet is a list, not a single item β€” that's the whole point, you can staple however much extra information you want onto an event. Some of that info is like, critical diagnostics πŸ”₯, other bits are just commentary vibes, and the debug flag is what tells you which is which.

For this facet, the details flag is the info itself. That info can be a string, or it can be a data structure you want displayed. Also important: this is one of the very few facet types that is allowed to contain blessed items. πŸ‘‘


πŸ’– LEGACY API πŸ’–

yeah okay these are the old-school accessors, they still work, they're still here, respect the elders.

  • $bool = $e->causes_fail β€” returns true if this event should make the test fail. In general though? It should be false. Don't be dramatic.
  • $bool = $e->increments_count β€” should be true if this event should bump the test count up by one. πŸ“ˆ
  • $e->callback($hub) β€” if your event needs to do extra little side-effects on the Test2::Hub, override this method. Heads up: this gets called BEFORE your event is handed over to the formatter. ⏰
  • $num = $e->nested β€” if this event is nested inside other events, this is the depth of that nesting. (It's mainly a subtests thing, iykyk.)
  • $bool = $e->global β€” set this to true if your event is global, like ALL threads and processes should see it no matter when or where it got generated. This is not a common want at all, it's used by bail-out and skip_all to actually end the testing. πŸ›‘
  • $code = $e->terminate β€” this one gets called AFTER your event has been passed to the formatter. It should normally return undef β€” only change that if your event should make the test exit immediately.

If you do want this event to kill the test, return the exit code here. Exit code 0 means exit success, any other integer means exit with failure.

Test2::Event::Plan uses this to exit 0 when the plan is 'skip_all'. Test2::Event::Bail also uses it to force the test to exit with a failure. πŸ’€

And why after the formatter? So the event is guaranteed to be seen and understood first. periodt.

  • $msg = $e->summary β€” meant to be a human-readable summary of the event. Ideally one line, but you can do multiple lines if you have to. This is for humans only, it does not need to be machine-friendly. The default is just returning the event package name. πŸŽ€
  • ($count, $directive, $reason) = $e->sets_plan() β€” checks whether this event sets the testing plan. If it doesn't, you get an empty list back. If it does, you get a list of 1 to 3 items, in this order: Expected Test Count, Test Directive, Reason for directive. πŸ“‹
  • $bool = $e->diagnostics β€” true if the event has diagnostics info in it. Why care? Because a non-verbose harness might straight up hide events that aren't in this category. And some formatters will send these to STDERR instead of STDOUT so they definitely get seen. πŸ‘€
  • $bool = $e->no_display β€” false by default. Returns true on events that formatters should not display. πŸ™ˆ
  • $id = $e->in_subtest β€” if the event is inside a subtest, this should hold the subtest ID.
  • $id = $e->subtest_id β€” if the event is a final subtest event, this should contain the subtest ID.

🌈 THIRD PARTY META-DATA 🌈

This object consumes Test2::Util::ExternalMeta, which gives you a consistent, no-chaos way to attach meta-data to instances of this class. Super handy for tools, plugins, and other extensions who wanna hang out. 🧚


⭐ SOURCE ⭐

The source code repository for Test2 can be found at https://github.com/Test-More/test-more/.

πŸ‘‘ MAINTAINERS πŸ‘‘

Chad Granum <exodist@cpan.org>

🌸 AUTHORS 🌸

Chad Granum <exodist@cpan.org>

Copyright Chad Granum <exodist@cpan.org>.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See https://dev.perl.org/licenses/


and that's the whole page bestie!! 🫢 this lil masterpiece is from perl v5.44.0, dated 2026-10-17 β€” go forth and build events that absolutely ate. πŸ’…βœ¨

πŸ“¦ where this page comes from
  • arch rolling: perl 5.44.0-1 Β· Artistic-1.0-Perl AND GPL-1.0-or-later
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms